package com.yc.testupload.controller;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.yc.testupload.util.DatabaseUtil;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import java.io.FileOutputStream;
import java.util.Properties;
import com.yc.testupload.util.EnvironmentManager;
import com.yc.testupload.service.WechatPublishProducer;
import com.yc.testupload.consumer.WechatPublishConsumer;
import com.yc.testupload.publisher.PlatformPublisherFactory;

/**
 * 文档列表数据接口Servlet
 * 提供从数据库查询文档数据的API，以及文档删除和状态管理功能
 */
@WebServlet({ "/api/documents", "/api/documents/*" })
public class DocumentsServlet extends HttpServlet {
    private static final Logger logger = LogManager.getLogger(DocumentsServlet.class);
    private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private EnvironmentManager environmentManager;
    private WechatPublishProducer publishProducer;
    private WechatPublishConsumer publishConsumer;
    private PlatformPublisherFactory publisherFactory;

    @Override
    public void init() throws ServletException {
        super.init();
        // 初始化环境管理器以获取配置信息
        environmentManager = EnvironmentManager.getInstance();
        logger.info("成功获取EnvironmentManager实例");

        // 初始化消息队列相关组件
        try {
            publishProducer = new WechatPublishProducer();
            publishConsumer = new WechatPublishConsumer(this);
            // 初始化平台发布器工厂
            publisherFactory = new PlatformPublisherFactory();
            // 将DocumentsServlet实例注入到微信发布器
            publisherFactory.setDocumentsServlet(this);
            // 启动消费者线程
            Thread consumerThread = new Thread(() -> publishConsumer.start());
            consumerThread.setDaemon(true);
            consumerThread.start();
            logger.info("微信公众号发布消息队列组件初始化完成");
            logger.info("平台发布器工厂初始化完成并注入DocumentsServlet实例");
        } catch (Exception e) {
            logger.error("初始化消息队列组件失败: {}", e.getMessage(), e);
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String pathInfo = request.getPathInfo();
        if (pathInfo == null || pathInfo.equals("/")) {
            // 处理文档列表请求
            handleGetDocuments(request, response);
        } else if (pathInfo.equals("/wechat/accounts")) {
            // 处理获取已授权公众号列表请求
            handleGetWechatAccounts(request, response);
        } else if (pathInfo.startsWith("/wechat/accounts/")) {
            // 处理获取单个公众号详情请求
            handleGetWechatAccountDetail(request, response, pathInfo);
        } else if (pathInfo.equals("/wechat/generate-auth-qrcode")) {
            // 处理生成授权二维码请求
            handleGenerateAuthQRCode(request, response);
        } else if (pathInfo.equals("/wechat/check-auth-status")) {
            // 处理检查授权状态请求
            handleCheckAuthStatus(request, response);
        } else {
            // 处理单个文档请求（如果需要）
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
        }
    }

    /**
     * 处理获取单个公众号详情的请求
     */
    private void handleGetWechatAccountDetail(HttpServletRequest request, HttpServletResponse response, String pathInfo)
            throws ServletException, IOException {
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter out = response.getWriter();
        JSONObject resultJson = new JSONObject();

        try {
            // 提取公众号ID
            String[] parts = pathInfo.split("/");
            if (parts.length < 4) {
                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                resultJson.put("code", 1);
                resultJson.put("message", "无效的公众号ID");
                out.write(resultJson.toString());
                return;
            }

            String accountId = parts[3];
            logger.info("查询公众号详情，ID: {}", accountId);

            // 获取公众号详情（包含app_secret）
            Map<String, String> accountInfo = getWechatAccountInfo(accountId);

            if (accountInfo != null) {
                response.setStatus(HttpServletResponse.SC_OK);
                resultJson.put("code", 0);
                resultJson.put("message", "success");

                // 创建一个新的JSONObject来确保所有字段都正确序列化
                JSONObject accountData = new JSONObject();
                // 直接使用从数据库获取的字段名，确保app_secret正确返回
                accountData.put("id", accountId);
                accountData.put("appid", accountInfo.get("appid")); // 使用正确的键名
                accountData.put("appId", accountInfo.get("appId")); // 同时保留驼峰命名
                accountData.put("authorizerAppid", accountInfo.get("authorizerAppid")); // 添加authorizerAppid
                // 确保从accountInfo中使用正确的键获取secret值
                String secretValue = accountInfo.get("app_secret");
                if (secretValue == null) {
                    secretValue = accountInfo.get("appSecret"); // 如果app_secret为null，尝试appSecret
                }
                accountData.put("app_secret", secretValue); // 确保前端需要的字段名
                accountData.put("appSecret", secretValue); // 同时保留驼峰命名
                accountData.put("refreshToken", accountInfo.get("refreshToken"));
                accountData.put("nickname", accountInfo.get("nickname"));
                accountData.put("account_name", accountInfo.get("nickname")); // 前端需要的字段名
                accountData.put("account_type", 0); // 添加缺失的字段
                accountData.put("auth_status", 1); // 添加缺失的字段
                accountData.put("head_img_url", "https://via.placeholder.com/40?text=" + accountInfo.get("nickname")); // 添加缺失的字段

                // 记录详细的日志，帮助调试
                logger.info("公众号详情数据 - ID:{}, AppID:{}, app_secret存在:{}, appSecret存在:{}, 返回Secret值:{}",
                        accountId, accountInfo.get("appid"), accountInfo.get("app_secret") != null,
                        accountInfo.get("appSecret") != null, secretValue != null ? "已获取" : "未获取");

                resultJson.put("data", accountData);
                logger.info("成功获取公众号详情，ID: {}, 名称: {}, AppID: {}, 最终返回Secret值: {}",
                        accountId, accountInfo.get("nickname"), accountInfo.get("appid"),
                        secretValue != null ? "已获取" : "未获取");
            } else {
                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
                resultJson.put("code", 2);
                resultJson.put("message", "公众号不存在");
                logger.warn("公众号不存在，ID: {}", accountId);
            }
        } catch (Exception e) {
            logger.error("获取公众号详情失败: {}", e.getMessage(), e);
            resultJson.put("code", 4);
            resultJson.put("message", "服务器内部错误");
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        } finally {
            out.write(resultJson.toString());
            out.flush();
            out.close();
        }
    }

    /**
     * 处理获取已授权公众号列表的请求
     */
    private void handleGetWechatAccounts(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter out = response.getWriter();
        JSONObject resultJson = new JSONObject();

        try {
            // 从数据库查询已授权的公众号列表
            List<Map<String, Object>> accounts = getWechatAccounts(request);

            // 构建响应结果
            resultJson.put("code", 0);
            resultJson.put("message", "success");
            resultJson.put("data", new JSONArray(accounts));

            response.setStatus(HttpServletResponse.SC_OK);
        } catch (Exception e) {
            logger.error("获取已授权公众号列表失败: {}", e.getMessage());
            resultJson.put("code", 4);
            resultJson.put("message", "服务器内部错误");
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        } finally {
            out.write(resultJson.toString());
            out.flush();
            out.close();
        }
    }

    /**
     * 处理检查授权状态的请求
     */
    private void handleCheckAuthStatus(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter out = response.getWriter();
        JSONObject resultJson = new JSONObject();

        try {
            // 检查session中是否有新的授权结果
            HttpSession session = request.getSession(false);
            Boolean authorized = false;

            if (session != null && session.getAttribute("wechatAuthResult") != null) {
                authorized = (Boolean) session.getAttribute("wechatAuthResult");
                // 清除session中的授权结果，避免重复处理
                session.removeAttribute("wechatAuthResult");
            }

            // 构建响应结果
            resultJson.put("code", 0);
            resultJson.put("message", "success");
            resultJson.put("data", new JSONObject().put("authorized", authorized));

            response.setStatus(HttpServletResponse.SC_OK);
        } catch (Exception e) {
            logger.error("检查授权状态失败: {}", e.getMessage());
            resultJson.put("code", 4);
            resultJson.put("message", "服务器内部错误");
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        } finally {
            out.write(resultJson.toString());
            out.flush();
            out.close();
        }
    }

    /**
     * 处理生成授权二维码的请求
     */
    private void handleGenerateAuthQRCode(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter out = response.getWriter();
        JSONObject resultJson = new JSONObject();

        try {
            // 生成授权二维码（实际项目中应该调用微信开放平台的API）
            // 这里使用模拟数据，实际应用中需要实现真正的二维码生成逻辑
            Map<String, String> qrCodeInfo = generateAuthQRCode();

            // 构建响应结果
            resultJson.put("code", 0);
            resultJson.put("message", "success");
            resultJson.put("data", new JSONObject(qrCodeInfo));

            response.setStatus(HttpServletResponse.SC_OK);
        } catch (Exception e) {
            logger.error("生成授权二维码失败: {}", e.getMessage());
            resultJson.put("code", 4);
            resultJson.put("message", "服务器内部错误");
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        } finally {
            out.write(resultJson.toString());
            out.flush();
            out.close();
        }
    }

    /**
     * 从数据库查询已授权的公众号列表
     */
    private List<Map<String, Object>> getWechatAccounts(HttpServletRequest request) {
        List<Map<String, Object>> accounts = new ArrayList<>();
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try {
            // 获取用户ID，直接从session中获取（与文档管理查询保持一致）
            Integer userId = (Integer) request.getSession().getAttribute("userId");
            if (userId == null) {
                userId = 0; // 默认值，确保SQL不会出错
                logger.info("会话中未找到用户ID，使用默认值: {}", userId);
            } else {
                logger.info("从session中获取userId: {}", userId);
            }

            logger.info("开始查询用户ID: {} 的已授权公众号列表", userId);

            conn = DatabaseUtil.getConnection();
            // 关联查询公众号信息和用户授权关系，根据用户ID筛选
            String sql = "SELECT woa.id, woa.appid, woa.account_name, ";
            sql += "woa.head_img_url, woa.account_type, ";
            sql += "uor.auth_status ";
            sql += "FROM wechat_official_account woa ";
            sql += "INNER JOIN user_official_account_relation uor ON woa.id = uor.official_account_id ";
            sql += "WHERE uor.auth_status = 1 AND uor.user_id = ?";

            logger.debug("准备执行查询公众号列表SQL: {}", sql);
            logger.debug("查询参数 - 用户ID: {}", userId);
            pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, userId);
            rs = pstmt.executeQuery();
            logger.info("SQL查询执行成功");

            int count = 0;
            while (rs.next()) {
                Map<String, Object> account = new HashMap<>();
                account.put("id", rs.getInt("id"));
                account.put("appid", rs.getString("appid"));
                account.put("account_name", rs.getString("account_name"));
                account.put("head_img_url", rs.getString("head_img_url"));
                account.put("account_type", rs.getInt("account_type"));
                account.put("auth_status", rs.getInt("auth_status"));

                accounts.add(account);
                count++;
                // 打印每个查询到的公众号的基本信息
                logger.info("查询到公众号 - ID: {}, 名称: {}, AppID: {}",
                        account.get("id"), account.get("account_name"), account.get("appid"));
            }

            logger.info("公众号查询完成，共查询到 {} 个已授权的公众号", count);
        } catch (Exception e) {
            logger.error("查询已授权公众号列表异常: {}", e.getMessage(), e);
            // 即使查询失败，也返回空列表而不是模拟数据
            return accounts;
        } finally {
            logger.debug("开始关闭数据库资源");
            if (rs != null) {
                try {
                    rs.close();
                    logger.debug("ResultSet已关闭");
                } catch (SQLException e) {
                    logger.error("关闭ResultSet失败", e);
                }
            }
            if (pstmt != null) {
                try {
                    pstmt.close();
                    logger.debug("PreparedStatement已关闭");
                } catch (SQLException e) {
                    logger.error("关闭PreparedStatement失败", e);
                }
            }
            DatabaseUtil.closeConnection(conn);
            logger.debug("数据库连接已关闭");
        }
        return accounts;
    }

    /**
     * 生成授权二维码（实际项目中应该调用微信开放平台的API）
     */
    private Map<String, String> generateAuthQRCode() {
        Map<String, String> qrCodeInfo = new HashMap<>();

        try {
            // 这里是模拟数据，实际应用中需要实现真正的二维码生成逻辑
            // 例如调用微信开放平台的API获取预授权码和授权链接
            // 然后使用第三方库生成二维码图片

            // 为了测试，我们使用一个在线二维码生成服务的链接
            String componentAppid = getComponentAppid();
            // 在实际应用中，应该调用微信开放平台API获取pre_auth_code
            String preAuthCode = "YOUR_PRE_AUTH_CODE";
            // 回调URI，需要在微信开放平台配置
            String redirectUri = "YOUR_REDIRECT_URI";

            String qrCodeUrl = "https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid="
                    +
                    componentAppid + "&pre_auth_code=" + preAuthCode + "&redirect_uri=" + redirectUri;
            String expiresIn = "5分钟";

            qrCodeInfo.put("qrCodeUrl", qrCodeUrl);
            qrCodeInfo.put("expiresIn", expiresIn);

        } catch (Exception e) {
            logger.error("生成授权二维码异常: {}", e.getMessage(), e);
            // 如果生成失败，返回一个默认的二维码链接
            qrCodeInfo.put("qrCodeUrl", "https://via.placeholder.com/150?text=Scan+QR+Code+to+Authorize");
            qrCodeInfo.put("expiresIn", "5分钟");
        }

        return qrCodeInfo;
    }

    /**
     * 处理获取文档列表的请求
     */
    private void handleGetDocuments(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter out = response.getWriter();
        JSONObject resultJson = new JSONObject();

        try {
            // 获取请求参数
            int page = getIntParameter(request, "page", 1);
            int pageSize = getIntParameter(request, "pageSize", 10);
            // 优先使用search参数，如果没有则使用title参数
            String title = request.getParameter("search") != null ? request.getParameter("search")
                    : (request.getParameter("title") != null ? request.getParameter("title") : "");
            String status = request.getParameter("status") != null ? request.getParameter("status") : "";
            // 优先使用type参数，如果没有则使用category参数
            String category = request.getParameter("type") != null ? request.getParameter("type")
                    : (request.getParameter("category") != null ? request.getParameter("category") : "");
            String username = request.getParameter("username") != null ? request.getParameter("username") : "";

            // 计算偏移量
            int offset = (page - 1) * pageSize;

            // 查询文档列表和总记录数
            List<Document> documents = getDocuments(request, title, status, category, username, pageSize, offset);
            int totalCount = getTotalCount(request, title, status, category, username);
            int totalPages = (int) Math.ceil((double) totalCount / pageSize);

            // 构建响应结果
            resultJson.put("code", 0);
            resultJson.put("message", "success");

            // 转换文档列表为JSONArray
            JSONArray dataArray = new JSONArray();
            for (Document doc : documents) {
                JSONObject docJson = new JSONObject();
                docJson.put("id", doc.getId());
                docJson.put("title", doc.getTitle());
                docJson.put("username", doc.getUsername());
                docJson.put("category", doc.getCategory());
                docJson.put("fileUrl", doc.getFileUrl());
                docJson.put("status", doc.getStatus());
                docJson.put("wenType", doc.getWenType());

                // 记录添加到JSON前的fileExt和fileSize值
                // logger.debug("Document ID: {}. fileExt to JSON: {}, fileSize to JSON: {}",
                // doc.getId(), doc.getFileExt(), doc.getFileSize());

                docJson.put("fileExt", doc.getFileExt());
                docJson.put("fileSize", doc.getFileSize());

                // 根据文档类型设置价格显示
                String wenType = doc.getWenType();
                if (wenType != null && wenType.equals("free")) {
                    docJson.put("price", "免费");
                } else if (wenType != null && (wenType.equals("pay") || wenType.equals("paid"))) {
                    docJson.put("price", doc.getPrice() != null ? doc.getPrice() : "0");
                } else {
                    docJson.put("price", doc.getPrice() != null ? doc.getPrice() : "");
                }

                docJson.put("addTime", doc.getAddTime());
                docJson.put("editTime", doc.getEditTime());
                dataArray.put(docJson);
            }

            resultJson.put("data", dataArray);
            resultJson.put("total", totalCount);
            resultJson.put("page", page);
            resultJson.put("pageSize", pageSize);
            resultJson.put("totalPages", totalPages);

            // Log the complete JSON response for debugging
            // logger.debug("Complete JSON response: {}", resultJson.toString());
        } catch (Exception e) {
            logger.error("获取文档列表失败: {}", e.getMessage());
            resultJson = new JSONObject();
            resultJson.put("code", 4);
            resultJson.put("message", "服务器内部错误");
        } finally {
            out.write(resultJson.toString());
            out.flush();
            out.close();
        }
    }

    /**
     * 从数据库获取微信公众号信息
     */
    /**
     * 根据appId获取微信公众号信息
     * 
     * @param appId 公众号AppID
     * @return 包含appId、appSecret、refreshToken和nickname的Map
     */
    private Map<String, String> getWechatAccountInfoByAppId(String appId) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try {
            conn = DatabaseUtil.getConnection();
            // 严格按照表结构只查询需要的字段
            String sql = "SELECT appid, app_secret, account_name FROM wechat_official_account WHERE appid = ?";
            logger.debug("准备执行根据appId查询公众号信息SQL: {}", sql);
            pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, appId);

            rs = pstmt.executeQuery();
            if (rs.next()) {
                Map<String, String> accountInfo = new HashMap<>();
                accountInfo.put("appId", rs.getString("appid"));
                accountInfo.put("appSecret", rs.getString("app_secret"));
                // 根据用户提供的表结构，没有refreshToken字段，返回空字符串
                accountInfo.put("refreshToken", "");
                accountInfo.put("nickname", rs.getString("account_name"));

                return accountInfo;
            }
        } catch (Exception e) {
            logger.error("根据appId获取微信公众号信息异常: {}", e.getMessage(), e);
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    logger.error("关闭ResultSet失败", e);
                }
            }
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    logger.error("关闭PreparedStatement失败", e);
                }
            }
            DatabaseUtil.closeConnection(conn);
        }
        return null;
    }

    /**
     * 检查指定用户是否已经关联了指定appid的公众号
     * 
     * @param userId 用户ID
     * @param appId  公众号AppID
     * @return 如果已关联返回true，否则返回false
     */
    private boolean isUserAccountRelationExists(Integer userId, String appId) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try {
            conn = DatabaseUtil.getConnection();
            // 查询用户是否已关联指定appid的公众号
            String sql = "SELECT COUNT(*) FROM user_official_account_relation uor " +
                    "JOIN wechat_official_account woa ON uor.official_account_id = woa.id " +
                    "WHERE uor.user_id = ? AND woa.appid = ? AND uor.auth_status = 1";
            logger.debug("准备执行检查用户公众号关联关系SQL: {}", sql);
            pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, userId);
            pstmt.setString(2, appId);

            rs = pstmt.executeQuery();
            if (rs.next()) {
                int count = rs.getInt(1);
                logger.debug("用户ID: {} 与 appId: {} 的关联记录数: {}", userId, appId, count);
                return count > 0;
            }
        } catch (Exception e) {
            logger.error("检查用户公众号关联关系异常: {}", e.getMessage(), e);
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    logger.error("关闭ResultSet失败", e);
                }
            }
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    logger.error("关闭PreparedStatement失败", e);
                }
            }
            DatabaseUtil.closeConnection(conn);
        }
        return false;
    }

    /**
     * 根据appId获取公众号ID
     * 
     * @param appId 公众号AppID
     * @return 公众号ID，如果未找到返回null
     */
    private Integer getOfficialAccountIdByAppId(String appId) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try {
            conn = DatabaseUtil.getConnection();
            String sql = "SELECT id FROM wechat_official_account WHERE appid = ?";
            logger.debug("准备执行根据appId获取公众号ID SQL: {}", sql);
            pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, appId);

            rs = pstmt.executeQuery();
            if (rs.next()) {
                int accountId = rs.getInt("id");
                logger.debug("根据appId: {} 获取到的公众号ID: {}", appId, accountId);
                return accountId;
            }
        } catch (Exception e) {
            logger.error("根据appId获取公众号ID异常: {}", e.getMessage(), e);
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    logger.error("关闭ResultSet失败", e);
                }
            }
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    logger.error("关闭PreparedStatement失败", e);
                }
            }
            DatabaseUtil.closeConnection(conn);
        }
        return null;
    }

    /**
     * 手动添加微信公众号到数据库
     * 
     * @param nickname  公众号名称
     * @param appId     公众号AppID
     * @param appSecret 公众号AppSecret
     * @param userId    用户ID
     * @return 是否添加成功
     */
    private boolean addWechatAccountManually(String nickname, String appId, String appSecret, Integer userId) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try {
            // 记录方法开始执行
            logger.debug("开始执行手动添加公众号操作");
            logger.info("用户ID: {} 尝试添加公众号: {}, AppID: {}", userId, nickname, appId);

            conn = DatabaseUtil.getConnection();
            conn.setAutoCommit(false); // 开启事务

            // 首先检查公众号是否已存在
            Integer existingAccountId = getOfficialAccountIdByAppId(appId);
            int accountId;

            if (existingAccountId != null) {
                // 公众号已存在，直接使用现有的公众号ID
                accountId = existingAccountId;
                logger.info("公众号已存在，appId: {} 对应的公众号ID: {}", appId, accountId);

                // 检查用户是否已关联该公众号
                boolean isRelationExists = isUserAccountRelationExists(userId, appId);
                if (isRelationExists) {
                    logger.warn("用户ID: {} 已经关联了公众号ID: {}，无需重复添加", userId, accountId);
                    return false; // 用户已关联，返回失败
                }
            } else {
                // 公众号不存在，需要创建新的公众号记录
                logger.info("公众号不存在，创建新的公众号记录，appId: {}", appId);

                // 插入公众号信息到wechat_official_account表，严格按照表结构字段
                String sql = "INSERT INTO wechat_official_account (appid, app_secret, account_name, account_type, head_img_url) VALUES (?, ?, ?, ?, ?)";
                logger.debug("准备执行SQL: {}", sql);
                pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
                pstmt.setString(1, appId);
                pstmt.setString(2, appSecret);
                pstmt.setString(3, nickname);
                pstmt.setInt(4, 0); // 默认服务号类型
                pstmt.setString(5, "https://via.placeholder.com/40?text=" + nickname); // 默认头像

                int rowsAffected = pstmt.executeUpdate();

                if (rowsAffected > 0) {
                    logger.info("公众号信息插入成功，受影响行数: {}", rowsAffected);

                    // 获取生成的公众号ID
                    rs = pstmt.getGeneratedKeys();
                    if (rs.next()) {
                        accountId = rs.getInt(1);
                        logger.debug("生成的公众号ID: {}", accountId);
                    } else {
                        logger.error("无法获取生成的公众号ID");
                        conn.rollback();
                        return false;
                    }
                } else {
                    logger.error("公众号信息插入失败");
                    conn.rollback();
                    return false;
                }
            }

            // 插入用户和公众号的关联关系，严格按照表结构字段
            String relationSql = "INSERT INTO user_official_account_relation (user_id, official_account_id, auth_status) VALUES (?, ?, 1)";
            logger.debug("准备执行关联关系SQL: {}", relationSql);
            PreparedStatement relationPstmt = conn.prepareStatement(relationSql);
            relationPstmt.setInt(1, userId);
            relationPstmt.setInt(2, accountId);
            relationPstmt.executeUpdate();
            logger.info("用户ID: {} 与公众号ID: {} 的关联关系建立成功", userId, accountId);
            relationPstmt.close();

            logger.debug("准备提交事务");
            conn.commit(); // 提交事务
            logger.info("手动添加公众号操作完成，结果: 成功");
            return true;
        } catch (Exception e) {
            logger.error("手动添加公众号异常: {}", e.getMessage(), e);
            if (conn != null) {
                try {
                    conn.rollback(); // 回滚事务
                } catch (SQLException ex) {
                    logger.error("事务回滚失败", ex);
                }
            }
            return false;
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    logger.error("关闭ResultSet失败", e);
                }
            }
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    logger.error("关闭PreparedStatement失败", e);
                }
            }
            DatabaseUtil.closeConnection(conn);
        }
    }

    /**
     * 获取第三方平台appid（从配置文件或环境变量中读取）
     */
    private String getComponentAppid() {
        // 在实际应用中，应该从配置文件或环境变量中读取
        // 这里返回一个默认值作为示例
        return "YOUR_COMPONENT_APPID";
    }

    /**
     * 获取第三方平台appsecret（从配置文件或环境变量中读取）
     */
    private String getComponentAppsecret() {
        // 在实际应用中，应该从配置文件或环境变量中读取
        // 这里返回一个默认值作为示例
        return "YOUR_COMPONENT_APPSECRET";
    }

    /**
     * 获取微信开放平台推送的verify_ticket
     */
    private String getComponentVerifyTicket() {
        // 在实际应用中，应该从数据库或缓存中读取最新的ticket
        // 这里返回一个默认值作为示例
        // 注意：verify_ticket是微信服务器定时推送的，需要实现回调接口接收
        return "YOUR_COMPONENT_VERIFY_TICKET";
    }

    /**
     * 获取微信公众号信息
     * 
     * @param accountId 公众号ID
     * @return 包含appId、appSecret、refreshToken和nickname的Map
     */
    private Map<String, String> getWechatAccountInfo(String accountId) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try {
            conn = DatabaseUtil.getConnection();
            String sql = "SELECT * FROM wechat_official_account WHERE id = ?";
            logger.debug("准备执行根据accountId查询公众号信息SQL: {}", sql);
            pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, accountId);

            rs = pstmt.executeQuery();
            if (rs.next()) {
                Map<String, String> accountInfo = new HashMap<>();
                // 添加兼容字段，支持多种可能的字段名
                accountInfo.put("appId", rs.getString("appid"));
                accountInfo.put("appid", rs.getString("appid"));
                accountInfo.put("authorizerAppid", rs.getString("appid")); // 添加authorizerAppid映射
                accountInfo.put("appSecret", rs.getString("app_secret"));
                accountInfo.put("app_secret", rs.getString("app_secret"));
                // 根据用户提供的表结构，没有refreshToken字段，返回空字符串
                accountInfo.put("refreshToken", "");
                accountInfo.put("nickname", rs.getString("account_name"));
                accountInfo.put("account_name", rs.getString("account_name"));
                // 添加其他可能需要的字段
                accountInfo.put("id", rs.getString("id"));

                try {
                    accountInfo.put("headImgUrl", rs.getString("head_img_url"));
                } catch (Exception e) {
                    logger.debug("head_img_url字段不存在: {}", e.getMessage());
                }

                try {
                    accountInfo.put("serviceTypeInfo", rs.getString("service_type_info"));
                } catch (Exception e) {
                    logger.debug("service_type_info字段不存在: {}", e.getMessage());
                }

                try {
                    accountInfo.put("status", rs.getString("status"));
                } catch (Exception e) {
                    logger.debug("status字段不存在: {}", e.getMessage());
                }

                logger.debug("公众号信息查询结果: appid={}, app_secret={}, nickname={}",
                        accountInfo.get("appid"), accountInfo.get("app_secret"), accountInfo.get("nickname"));

                return accountInfo;
            }
        } catch (Exception e) {
            logger.error("获取微信公众号信息异常: {}", e.getMessage(), e);
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    logger.error("关闭ResultSet失败", e);
                }
            }
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    logger.error("关闭PreparedStatement失败", e);
                }
            }
            DatabaseUtil.closeConnection(conn);
        }
        return null;
    }

    /**
     * 从数据库查询文档列表
     */
    private List<Document> getDocuments(HttpServletRequest request, String title, String status, String category,
            String username, int pageSize,
            int offset) {
        List<Document> documents = new ArrayList<>();
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try {
            conn = DatabaseUtil.getConnection();
            StringBuilder sql = new StringBuilder();
            sql.append("SELECT w.*, f.file_url, f.file_ext, f.file_size ");
            sql.append("FROM wk_wenku w ");
            sql.append("LEFT JOIN wk_file f ON w.file_id = f.file_id ");
            sql.append("WHERE 1=1 ");
            // 从会话中获取当前登录用户的user_id
            Integer userId = (Integer) request.getSession().getAttribute("userId");
            if (userId == null) {
                userId = 0; // 默认值，确保SQL不会出错
            }
            sql.append("AND w.user_id = ? ");

            // 添加搜索条件 - 只使用存在的列
            List<String> params = new ArrayList<>();
            params.add(userId.toString());
            if (!title.isEmpty()) {
                sql.append("AND w.title LIKE ? ");
                params.add("%" + title + "%");
            }
            if (!status.isEmpty()) {
                sql.append("AND w.status = ? ");
                params.add(status);
            }
            // 移除对不存在的t.type_name和u.username列的引用
            // 保留type和username参数但不实际使用它们进行过滤，以保持API兼容性

            // 添加排序和分页
            sql.append("ORDER BY w.add_time DESC ");
            sql.append("LIMIT ? OFFSET ?");

            pstmt = conn.prepareStatement(sql.toString());
            int paramIndex = 1;
            // 设置搜索参数
            for (String param : params) {
                pstmt.setString(paramIndex++, param);
            }
            // 设置分页参数
            pstmt.setInt(paramIndex++, pageSize);
            pstmt.setInt(paramIndex, offset);

            logger.info("执行查询文档列表SQL: {}", sql.toString());
            rs = pstmt.executeQuery();

            // 处理查询结果
            while (rs.next()) {
                Document doc = new Document();
                // 假设主键列名是id而不是wen_id
                doc.setId(rs.getInt("id"));
                doc.setTitle(rs.getString("title"));
                // 动态设置用户名
                doc.setUsername(userId != null ? "user_" + userId : "user_0");

                // 尝试获取文件后缀和大小
                try {
                    String fileExt = rs.getString("file_ext");
                    doc.setFileExt(fileExt);
                    // logger.debug("Document ID: {}. FileExt from DB: {}", rs.getInt("id"),
                    // fileExt);
                } catch (SQLException e) {
                    doc.setFileExt("");
                    logger.error("Failed to get file_ext for document ID: {}", rs.getInt("id"), e);
                }
                try {
                    long fileSize = rs.getLong("file_size");
                    doc.setFileSize(fileSize);
                    // logger.debug("Document ID: {}. FileSize from DB: {}", rs.getInt("id"),
                    // fileSize);
                } catch (SQLException e) {
                    doc.setFileSize(0);
                    logger.error("Failed to get file_size for document ID: {}", rs.getInt("id"), e);
                }

                doc.setFileUrl(rs.getString("file_url"));
                doc.setStatus(rs.getInt("status"));
                doc.setWenType(rs.getString("wen_type"));

                // 获取type_id字段
                try {
                    int typeId = rs.getInt("type_id");
                    doc.setTypeId(typeId);

                    // 根据type_id设置分类名称
                    switch (typeId) {
                        case 1:
                            doc.setCategory("创业");
                            break;
                        case 2:
                            doc.setCategory("战略管理");
                            break;
                        case 7:
                            doc.setCategory("数字化");
                            break;
                        case 8:
                            doc.setCategory("智慧城市/工业");
                            break;
                        case 9:
                            doc.setCategory("元宇宙/WEB3");
                            break;
                        case 13:
                            doc.setCategory("团队管理");
                            break;
                        case 14:
                            doc.setCategory("研发管理");
                            break;
                        case 15:
                            doc.setCategory("项目管理");
                            break;
                        case 18:
                            doc.setCategory("数据治理");
                            break;
                        case 19:
                            doc.setCategory("数字化转型");
                            break;
                        case 20:
                            doc.setCategory("大数据/中台");
                            break;
                        case 22:
                            doc.setCategory("职场思维");
                            break;
                        case 23:
                            doc.setCategory("流程与规范");
                            break;
                        case 24:
                            doc.setCategory("人工智能");
                            break;
                        case 25:
                            doc.setCategory("绩效管理");
                            break;
                        case 26:
                            doc.setCategory("架构设计/实践");
                            break;
                        case 27:
                            doc.setCategory("模板范本");
                            break;
                        case 28:
                            doc.setCategory("投融资");
                            break;
                        case 29:
                            doc.setCategory("合同范本");
                            break;
                        case 30:
                            doc.setCategory("软件开发");
                            break;
                        case 31:
                            doc.setCategory("面试题");
                            break;
                        case 32:
                            doc.setCategory("人力资源");
                            break;
                        case 33:
                            doc.setCategory("公司与股权");
                            break;
                        case 34:
                            doc.setCategory("技术前瞻");
                            break;
                        case 35:
                            doc.setCategory("商业计划书");
                            break;
                        case 36:
                            doc.setCategory("数字孪生");
                            break;
                        case 37:
                            doc.setCategory("干部与人才");
                            break;
                        case 38:
                            doc.setCategory("入党申请");
                            break;
                        case 39:
                            doc.setCategory("教育行业");
                            break;
                        case 40:
                            doc.setCategory("基础教育");
                            break;
                        case 41:
                            doc.setCategory("职场必备");
                            break;
                        case 42:
                            doc.setCategory("逻辑排版");
                            break;
                        case 43:
                            doc.setCategory("RPA/机器人");
                            break;
                        case 44:
                            doc.setCategory("销售与培训");
                            break;
                        case 45:
                            doc.setCategory("年终终结");
                            break;
                        case 46:
                            doc.setCategory("实时计算");
                            break;
                        case 47:
                            doc.setCategory("开发规范");
                            break;
                        case 48:
                            doc.setCategory("数据埋点");
                            break;
                        case 49:
                            doc.setCategory("信息与安全");
                            break;
                        case 50:
                            doc.setCategory("算法");
                            break;
                        case 51:
                            doc.setCategory("政策文件");
                            break;
                        case 52:
                            doc.setCategory("数据库");
                            break;
                        case 53:
                            doc.setCategory("芯产业");
                            break;
                        case 54:
                            doc.setCategory("产业洞察");
                            break;
                        case 55:
                            doc.setCategory("芯片制造");
                            break;
                        case 56:
                            doc.setCategory("质量管理");
                            break;
                        case 57:
                            doc.setCategory("画像/推荐系统");
                            break;
                        case 59:
                            doc.setCategory("云计算/云原生");
                            break;
                        case 60:
                            doc.setCategory("市场调研");
                            break;
                        case 61:
                            doc.setCategory("DEVPOS/运维");
                            break;
                        case 62:
                            doc.setCategory("大学教育");
                            break;
                        case 63:
                            doc.setCategory("办公技巧");
                            break;
                        case 64:
                            doc.setCategory("财务/税务");
                            break;
                        case 66:
                            doc.setCategory("linux");
                            break;
                        case 67:
                            doc.setCategory("企业架构与经营");
                            break;
                        case 68:
                            doc.setCategory("供应链/物流");
                            break;
                        case 69:
                            doc.setCategory("智慧农业");
                            break;
                        case 70:
                            doc.setCategory("边缘/隐私计算");
                            break;
                        case 71:
                            doc.setCategory("前端");
                            break;
                        case 72:
                            doc.setCategory("安防监控");
                            break;
                        case 73:
                            doc.setCategory("汽车产业");
                            break;
                        case 74:
                            doc.setCategory("医疗健康");
                            break;
                        case 75:
                            doc.setCategory("卫星与通信");
                            break;
                        case 76:
                            doc.setCategory("操作系统");
                            break;
                        case 77:
                            doc.setCategory("金融银行");
                            break;
                        case 78:
                            doc.setCategory("物联网");
                            break;
                        case 79:
                            doc.setCategory("思维模型");
                            break;
                        case 80:
                            doc.setCategory("PPT模板");
                            break;
                        case 81:
                            doc.setCategory("简历模板");
                            break;
                        case 82:
                            doc.setCategory("述职报告");
                            break;
                        case 83:
                            doc.setCategory("搜索引擎");
                            break;
                        case 84:
                            doc.setCategory("公务员教育");
                            break;
                        case 85:
                            doc.setCategory("产品设计");
                            break;
                        case 86:
                            doc.setCategory("行业模板");
                            break;
                        case 87:
                            doc.setCategory("游戏");
                            break;
                        case 88:
                            doc.setCategory("新能源");
                            break;
                        case 89:
                            doc.setCategory("招投标");
                            break;
                        case 90:
                            doc.setCategory("面试题");
                            break;
                        case 91:
                            doc.setCategory("数据库");
                            break;
                        default:
                            doc.setCategory("默认分类");
                    }
                } catch (SQLException e) {
                    // 如果没有type_id字段或获取失败，使用默认分类
                    doc.setTypeId(0);
                    doc.setCategory("默认分类");
                    logger.error("Failed to get type_id for document ID: {}", rs.getInt("id"), e);
                }

                // 尝试不同的可能的价格列名
                try {
                    doc.setPrice(rs.getBigDecimal("file_jine"));
                } catch (SQLException e) {
                    try {
                        doc.setPrice(rs.getBigDecimal("price"));
                    } catch (SQLException ex) {
                        // 如果都不存在，设置为null
                        doc.setPrice(null);
                    }
                }
                // 尝试处理日期列 - 注意：数据库中的add_time可能是LONG类型的时间戳
                try {
                    // 首先尝试作为LONG类型的时间戳获取
                    try {
                        long timeStamp = rs.getLong("add_time");
                        if (timeStamp > 0) {
                            // 检查时间戳是否为秒级（如果小于2000000000000，可能是秒级时间戳）
                            if (timeStamp < 2000000000000L) {
                                // 转换为毫秒级时间戳
                                timeStamp = timeStamp * 1000;
                            }
                            Date date = new Date(timeStamp);
                            doc.setAddTime(dateFormat.format(date));
                        } else {
                            doc.setAddTime("");
                        }
                    } catch (SQLException e1) {
                        // 如果作为LONG获取失败，尝试作为Timestamp获取
                        try {
                            Timestamp addTime = rs.getTimestamp("add_time");
                            if (addTime != null) {
                                doc.setAddTime(dateFormat.format(addTime));
                            } else {
                                doc.setAddTime("");
                            }
                        } catch (SQLException e2) {
                            doc.setAddTime("");
                            logger.error("Failed to get add_time for document ID: {}", rs.getInt("id"), e2);
                        }
                    }
                } catch (Exception e) {
                    doc.setAddTime("");
                    logger.error("Unexpected error when processing add_time: {}", e.getMessage());
                }
                try {
                    // 首先尝试作为LONG类型的时间戳获取edit_time
                    try {
                        long editTimeStamp = rs.getLong("edit_time");
                        if (editTimeStamp > 0) {
                            // 检查时间戳是否为秒级
                            if (editTimeStamp < 2000000000000L) {
                                // 转换为毫秒级时间戳
                                editTimeStamp = editTimeStamp * 1000;
                            }
                            Date editDate = new Date(editTimeStamp);
                            doc.setEditTime(dateFormat.format(editDate));
                        } else {
                            doc.setEditTime("");
                        }
                    } catch (SQLException e1) {
                        // 如果作为LONG获取失败，尝试作为Timestamp获取
                        try {
                            Timestamp editTime = rs.getTimestamp("edit_time");
                            if (editTime != null) {
                                doc.setEditTime(dateFormat.format(editTime));
                            } else {
                                doc.setEditTime("");
                            }
                        } catch (SQLException e2) {
                            doc.setEditTime("");
                            logger.error("Failed to get edit_time for document ID: {}", rs.getInt("id"), e2);
                        }
                    }
                } catch (Exception e) {
                    doc.setEditTime("");
                    logger.error("Unexpected error when processing edit_time: {}", e.getMessage());
                }
                documents.add(doc);
            }
        } catch (SQLException e) {
            logger.error("查询文档列表失败: {}", e.getMessage());
        } finally {
            // 关闭资源
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    logger.error("关闭ResultSet失败", e);
                }
            }
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    logger.error("关闭PreparedStatement失败", e);
                }
            }
            DatabaseUtil.closeConnection(conn);
        }

        return documents;
    }

    /**
     * 获取总记录数
     */
    private int getTotalCount(HttpServletRequest request, String title, String status, String category,
            String username) {
        int totalCount = 0;
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try {
            conn = DatabaseUtil.getConnection();
            StringBuilder sql = new StringBuilder();
            sql.append("SELECT COUNT(*) as count ");
            sql.append("FROM wk_wenku w ");
            sql.append("LEFT JOIN wk_file f ON w.file_id = f.file_id ");
            sql.append("WHERE 1=1 ");
            // 从会话中获取当前登录用户的user_id
            Integer userId = (Integer) request.getSession().getAttribute("userId");
            if (userId == null) {
                userId = 0; // 默认值，确保SQL不会出错
            }
            sql.append("AND w.user_id = ? ");

            // 添加搜索条件 - 只使用存在的列
            List<String> params = new ArrayList<>();
            params.add(userId.toString());
            if (!title.isEmpty()) {
                sql.append("AND w.title LIKE ? ");
                params.add("%" + title + "%");
            }
            if (!status.isEmpty()) {
                sql.append("AND w.status = ? ");
                params.add(status);
            }
            // 移除对不存在的t.type_name和u.username列的引用
            // 保留type和username参数但不实际使用它们进行过滤，以保持API兼容性

            pstmt = conn.prepareStatement(sql.toString());
            int paramIndex = 1;
            for (String param : params) {
                pstmt.setString(paramIndex++, param);
            }

            rs = pstmt.executeQuery();
            if (rs.next()) {
                totalCount = rs.getInt("count");
            }
        } catch (SQLException e) {
            logger.error("获取文档总数失败: {}", e.getMessage());
        } finally {
            // 关闭资源
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    logger.error("关闭ResultSet失败", e);
                }
            }
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    logger.error("关闭PreparedStatement失败", e);
                }
            }
            DatabaseUtil.closeConnection(conn);
        }

        return totalCount;
    }

    /**
     * 处理DELETE请求 - 删除单个文档
     */
    @Override
    protected void doDelete(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter out = response.getWriter();
        JSONObject resultJson = new JSONObject();

        try {
            // 获取路径信息
            String pathInfo = request.getPathInfo();
            if (pathInfo == null || pathInfo.equals("/")) {
                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                resultJson.put("code", 1);
                resultJson.put("message", "请求路径不能为空");
                out.write(resultJson.toString());
                return;
            }

            // 检查是否是删除公众号请求
            if (pathInfo.startsWith("/wechat/accounts/")) {
                // 处理删除公众号请求
                String[] parts = pathInfo.split("/");
                if (parts.length < 4) {
                    response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                    resultJson.put("code", 1);
                    resultJson.put("message", "无效的公众号ID");
                    out.write(resultJson.toString());
                    return;
                }

                String accountId = parts[3];
                // 执行删除公众号操作
                deleteWechatAccount(request, accountId);

                response.setStatus(HttpServletResponse.SC_OK);
                resultJson.put("code", 0);
                resultJson.put("message", "删除成功");
            } else {
                // 处理删除文档请求
                String[] parts = pathInfo.split("/");
                if (parts.length < 2) {
                    response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                    resultJson.put("code", 1);
                    resultJson.put("message", "无效的文档ID");
                    out.write(resultJson.toString());
                    return;
                }

                int documentId = Integer.parseInt(parts[1]);

                // 执行删除文档操作
                deleteDocument(request, documentId);

                response.setStatus(HttpServletResponse.SC_OK);
                resultJson.put("code", 0);
                resultJson.put("message", "删除成功");
            }
        } catch (NumberFormatException e) {
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            resultJson.put("code", 1);
            resultJson.put("message", "无效的ID格式");
            logger.error("无效的ID格式", e);
        } catch (Exception e) {
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            resultJson.put("code", 2);
            resultJson.put("message", "服务器内部错误");
            logger.error("删除操作失败", e);
        } finally {
            out.write(resultJson.toString());
            out.flush();
            out.close();
        }
    }

    /**
     * 删除微信公众号
     * 注意：实际删除的是用户与公众号的关联关系，而不是公众号本身
     */
    private void deleteWechatAccount(HttpServletRequest request, String accountId) throws SQLException {
        Connection conn = null;
        PreparedStatement pstmt = null;

        try {
            conn = DatabaseUtil.getConnection();
            // 从会话中获取当前登录用户的user_id
            Integer userId = (Integer) request.getSession().getAttribute("userId");
            if (userId == null) {
                userId = 0; // 默认值，确保SQL不会出错
                logger.warn("会话中未找到用户ID，使用默认值: {}", userId);
            }

            logger.info("开始删除用户ID: {} 与公众号ID: {} 的关联关系", userId, accountId);

            // 删除用户与公众号的关联关系
            String sql = "DELETE FROM user_official_account_relation WHERE official_account_id = ? AND user_id = ?";
            pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, accountId);
            pstmt.setInt(2, userId);

            int affectedRows = pstmt.executeUpdate();
            logger.info("删除公众号关联关系，影响行数: {}", affectedRows);

            if (affectedRows == 0) {
                logger.warn("未找到用户ID: {} 与公众号ID: {} 的关联关系", userId, accountId);
            }
        } finally {
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    logger.error("关闭PreparedStatement失败", e);
                }
            }
            DatabaseUtil.closeConnection(conn);
        }
    }

    /**
     * 处理POST请求 - 批量删除文档和发布到公众号
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter out = response.getWriter();
        JSONObject resultJson = new JSONObject();

        try {
            String pathInfo = request.getPathInfo();

            // 处理批量删除请求
            if (pathInfo != null && pathInfo.equals("/batch-delete")) {
                // 读取请求体中的JSON数据
                BufferedReader reader = request.getReader();
                StringBuilder sb = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    sb.append(line);
                }

                // 解析JSON数组
                JSONArray idsArray = new JSONArray(sb.toString());
                List<Integer> ids = new ArrayList<>();
                for (int i = 0; i < idsArray.length(); i++) {
                    ids.add(idsArray.getInt(i));
                }

                // 执行批量删除
                batchDeleteDocuments(request, ids);

                response.setStatus(HttpServletResponse.SC_OK);
                resultJson.put("code", 0);
                resultJson.put("message", "批量删除成功");
            }
            // 处理多个文档发布到多个公众号请求
            else if (pathInfo != null && pathInfo.equals("/batch-publish-to-multiple-wechat")) {
                try {
                    logger.info("接收到多个文档发布到多个公众号请求");

                    // 从请求体获取JSON数据
                    BufferedReader reader = request.getReader();
                    StringBuilder sb = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        sb.append(line);
                    }
                    String requestBody = sb.toString();
                    logger.debug("多个文档发布到多个公众号请求体内容: {}", requestBody);

                    JSONObject jsonBody = new JSONObject(requestBody);
                    JSONArray documentsArray = jsonBody.getJSONArray("documents");
                    JSONArray accountIdsArray = jsonBody.getJSONArray("accountIds");

                    // 验证参数
                    if (documentsArray == null || documentsArray.length() == 0) {
                        logger.warn("多个文档多公众号发布参数验证失败: 文档列表为空");
                        response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                        resultJson.put("code", 1);
                        resultJson.put("message", "请选择要发布的文档");
                        out.write(resultJson.toString());
                        return;
                    }

                    if (accountIdsArray == null || accountIdsArray.length() == 0) {
                        logger.warn("多个文档多公众号发布参数验证失败: 公众号列表为空");
                        response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                        resultJson.put("code", 1);
                        resultJson.put("message", "请选择要发布的公众号");
                        out.write(resultJson.toString());
                        return;
                    }

                    // 验证每个文档对象的有效性
                    for (int i = 0; i < documentsArray.length(); i++) {
                        JSONObject docObj = documentsArray.getJSONObject(i);
                        if (!docObj.has("id") || docObj.isNull("id")) {
                            logger.warn("多个文档多公众号发布参数验证失败: 缺少文档ID");
                            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                            resultJson.put("code", 1);
                            resultJson.put("message", "无效的文档信息：缺少文档ID");
                            out.write(resultJson.toString());
                            return;
                        }
                        int documentId = docObj.getInt("id");
                        if (documentId <= 0) {
                            logger.warn("多个文档多公众号发布参数验证失败: 文档ID无效: {}", documentId);
                            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                            resultJson.put("code", 1);
                            resultJson.put("message", "无效的文档ID");
                            out.write(resultJson.toString());
                            return;
                        }
                        // 确保文档对象包含title字段
                        if (!docObj.has("title") || docObj.isNull("title")) {
                            docObj.put("title", "");
                        }
                    }

                    // 准备公众号ID列表
                    List<String> accountIds = new ArrayList<>();
                    for (int i = 0; i < accountIdsArray.length(); i++) {
                        Object accountIdObj = accountIdsArray.get(i);
                        accountIds.add(accountIdObj.toString());
                    }

                    logger.info("多个文档多公众号发布 - 文档数量: {}, 公众号数量: {}", documentsArray.length(), accountIds.size());

                    // 准备发布任务数据
                    Map<String, Object> taskData = new HashMap<>();
                    taskData.put("taskType", "MULTIPLE_DOCS_MULTIPLE_ACCOUNTS");
                    taskData.put("documents", documentsArray);
                    taskData.put("accountIds", accountIdsArray);

                    // 发送到消息队列，实现异步处理
                    String taskId = publishProducer.sendPublishTask(taskData);

                    logger.info("多文档多公众号发布任务已加入队列，任务ID: {}", taskId);

                    response.setStatus(HttpServletResponse.SC_OK);
                    resultJson.put("code", 0);
                    resultJson.put("message", "发布任务已成功加入队列，系统将异步处理，请稍后查看结果");
                    resultJson.put("taskId", taskId);
                } catch (Exception e) {
                    logger.error("处理多个文档多公众号发布请求异常: {}", e.getMessage(), e);
                    response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                    resultJson.put("code", 4);
                    resultJson.put("message", "服务器内部错误: " + e.getMessage());
                }
            }
            // 处理单个文档多公众号发布请求
            else if (pathInfo != null && pathInfo.equals("/publish-to-multiple-wechat")) {
                try {
                    logger.info("接收到单个文档多公众号发布请求");

                    // 从请求体获取JSON数据
                    BufferedReader reader = request.getReader();
                    StringBuilder sb = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        sb.append(line);
                    }
                    String requestBody = sb.toString();
                    logger.debug("单个文档多公众号发布请求体内容: {}", requestBody);

                    JSONObject jsonBody = new JSONObject(requestBody);
                    int documentId = jsonBody.getInt("documentId");
                    JSONArray accountIdsArray = jsonBody.getJSONArray("accountIds");

                    // 验证参数
                    if (documentId <= 0) {
                        logger.warn("单个文档多公众号发布参数验证失败: 文档ID无效");
                        response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                        resultJson.put("code", 1);
                        resultJson.put("message", "无效的文档ID");
                        out.write(resultJson.toString());
                        return;
                    }

                    if (accountIdsArray == null || accountIdsArray.length() == 0) {
                        logger.warn("单个文档多公众号发布参数验证失败: 公众号列表为空");
                        response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                        resultJson.put("code", 1);
                        resultJson.put("message", "请选择要发布的公众号");
                        out.write(resultJson.toString());
                        return;
                    }

                    // 准备公众号ID列表
                    List<String> accountIds = new ArrayList<>();
                    for (int i = 0; i < accountIdsArray.length(); i++) {
                        Object accountIdObj = accountIdsArray.get(i);
                        accountIds.add(accountIdObj.toString());
                    }

                    logger.info("单个文档多公众号发布 - 文档ID: {}, 公众号数量: {}", documentId, accountIds.size());

                    // 创建文档数组以便复用已有的多公众号发布方法
                    JSONArray documentsArray = new JSONArray();
                    JSONObject docObj = new JSONObject();
                    docObj.put("id", documentId);
                    // 尝试获取文档标题，如果没有则使用空字符串
                    try {
                        docObj.put("title", jsonBody.getString("documentTitle"));
                    } catch (Exception e) {
                        docObj.put("title", "");
                    }
                    documentsArray.put(docObj);

                    // 准备发布任务数据
                    Map<String, Object> taskData = new HashMap<>();
                    taskData.put("taskType", "SINGLE_DOC_MULTIPLE_ACCOUNTS");
                    taskData.put("documentId", documentId);
                    taskData.put("documentTitle", jsonBody.optString("documentTitle", ""));
                    taskData.put("accountIds", accountIdsArray);

                    // 发送到消息队列，实现异步处理
                    String taskId = publishProducer.sendPublishTask(taskData);

                    logger.info("单文档多公众号发布任务已加入队列，任务ID: {}", taskId);

                    response.setStatus(HttpServletResponse.SC_OK);
                    resultJson.put("code", 0);
                    resultJson.put("message", "发布任务已成功加入队列，系统将异步处理，请稍后查看结果");
                    resultJson.put("taskId", taskId);
                } catch (Exception e) {
                    logger.error("处理单个文档多公众号发布请求异常: {}", e.getMessage(), e);
                    response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                    resultJson.put("code", 4);
                    resultJson.put("message", "服务器内部错误: " + e.getMessage());
                }
            }
            // 处理发布到公众号请求
            else if (pathInfo != null && pathInfo.matches("^/\\d+/publish-to-wechat$")) {
                // 提取文档ID
                String[] parts = pathInfo.split("/");
                if (parts.length < 3) {
                    response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                    resultJson.put("code", 1);
                    resultJson.put("message", "请求路径格式不正确");
                    out.write(resultJson.toString());
                    return;
                }

                int documentId = Integer.parseInt(parts[1]);

                // 获取公众号ID参数 - 兼容前端发送的officialAccountId
                String accountId = null;
                try {
                    // 记录请求头信息
                    String contentType = request.getContentType();
                    logger.info("请求Content-Type: {}", contentType);

                    // 从请求体获取JSON数据
                    StringBuilder sb = new StringBuilder();
                    try (BufferedReader reader = request.getReader()) {
                        String line;
                        while ((line = reader.readLine()) != null) {
                            sb.append(line);
                        }
                    }

                    String requestBody = sb.toString();
                    logger.info("发布到公众号请求体内容: [{}]", requestBody);

                    if (!requestBody.isEmpty() && !requestBody.trim().equals("{}")) {
                        JSONObject jsonBody = new JSONObject(requestBody);
                        logger.info("解析后的JSON对象: {}", jsonBody.toString());

                        // 尝试多种可能的字段名
                        if (jsonBody.has("officialAccountId")) {
                            // 处理整数类型的officialAccountId
                            Object officialAccountIdObj = jsonBody.get("officialAccountId");
                            if (officialAccountIdObj instanceof Integer) {
                                accountId = String.valueOf((Integer) officialAccountIdObj);
                            } else if (officialAccountIdObj instanceof String) {
                                accountId = (String) officialAccountIdObj;
                            } else {
                                accountId = officialAccountIdObj.toString();
                            }
                            logger.info("从officialAccountId字段获取到accountId: {} (原始类型: {})", accountId,
                                    officialAccountIdObj.getClass().getSimpleName());
                        } else if (jsonBody.has("accountId")) {
                            // 处理整数类型的accountId
                            Object accountIdObj = jsonBody.get("accountId");
                            if (accountIdObj instanceof Integer) {
                                accountId = String.valueOf((Integer) accountIdObj);
                            } else if (accountIdObj instanceof String) {
                                accountId = (String) accountIdObj;
                            } else {
                                accountId = accountIdObj.toString();
                            }
                            logger.info("从accountId字段获取到accountId: {} (原始类型: {})", accountId,
                                    accountIdObj.getClass().getSimpleName());
                        } else {
                            logger.warn("请求体中未找到accountId相关字段，可用字段: {}", jsonBody.keySet());
                        }
                    } else {
                        logger.warn("请求体为空或只包含空对象");
                    }
                } catch (Exception e) {
                    logger.error("解析请求体失败: {}", e.getMessage(), e);
                }

                // 如果从请求体没有获取到，尝试从URL参数获取
                if (accountId == null || accountId.isEmpty()) {
                    accountId = request.getParameter("accountId");
                }

                // 准备发布任务数据
                Map<String, Object> taskData = new HashMap<>();
                taskData.put("taskType", "SINGLE_DOC_SINGLE_ACCOUNT");
                taskData.put("documentId", documentId);
                taskData.put("accountId", accountId);

                // 发送到消息队列，实现异步处理
                String taskId = publishProducer.sendPublishTask(taskData);

                logger.info("单文档单公众号发布任务已加入队列，任务ID: {}", taskId);

                response.setStatus(HttpServletResponse.SC_OK);
                resultJson.put("code", 0);
                resultJson.put("message", "发布任务已成功加入队列，系统将异步处理，请稍后查看结果");
                resultJson.put("taskId", taskId);
            }
            // 处理批量发布到公众号请求
            else if (pathInfo != null && pathInfo.equals("/batch-publish-to-wechat")) {
                try {
                    logger.info("接收到批量发布到公众号请求");

                    // 从请求体获取JSON数据
                    BufferedReader reader = request.getReader();
                    StringBuilder sb = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        sb.append(line);
                    }
                    String requestBody = sb.toString();
                    logger.debug("批量发布请求体内容: {}", requestBody);

                    JSONObject jsonBody = new JSONObject(requestBody);
                    JSONArray documentsArray = jsonBody.getJSONArray("documents");

                    // 验证文档列表
                    if (documentsArray == null || documentsArray.length() == 0) {
                        logger.warn("批量发布参数验证失败: 文档列表为空");
                        response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                        resultJson.put("code", 1);
                        resultJson.put("message", "请选择要发布的文档");
                        out.write(resultJson.toString());
                        return;
                    }

                    // 检查是否有多个公众号ID数组
                    JSONArray accountIdsArray = jsonBody.optJSONArray("accountIds");

                    if (accountIdsArray != null && accountIdsArray.length() > 0) {
                        // 多公众号发布模式
                        logger.info("多公众号发布请求 - 公众号数量: {}, 文档数量: {}", accountIdsArray.length(),
                                documentsArray.length());

                        // 准备发布任务数据
                        Map<String, Object> taskData = new HashMap<>();
                        taskData.put("taskType", "MULTIPLE_DOCS_MULTIPLE_ACCOUNTS");
                        taskData.put("documents", documentsArray);
                        taskData.put("accountIds", accountIdsArray);

                        // 发送到消息队列，实现异步处理
                        String taskId = publishProducer.sendPublishTask(taskData);

                        logger.info("多文档多公众号发布任务已加入队列，任务ID: {}", taskId);

                        response.setStatus(HttpServletResponse.SC_OK);
                        resultJson.put("code", 0);
                        resultJson.put("message", "发布任务已成功加入队列，系统将异步处理，请稍后查看结果");
                        resultJson.put("taskId", taskId);
                    } else {
                        // 兼容旧版单公众号发布模式
                        String officialAccountId;
                        if (jsonBody.has("officialAccountId")) {
                            Object accountIdObj = jsonBody.get("officialAccountId");
                            officialAccountId = accountIdObj.toString();
                            logger.debug("获取到的公众号ID类型: {}, 值: {}", accountIdObj.getClass().getName(),
                                    officialAccountId);
                        } else if (jsonBody.has("accountId")) {
                            Object accountIdObj = jsonBody.get("accountId");
                            officialAccountId = accountIdObj.toString();
                            logger.debug("从accountId获取到的公众号ID类型: {}, 值: {}", accountIdObj.getClass().getName(),
                                    officialAccountId);
                        } else {
                            logger.error("JSON请求中缺少公众号ID参数");
                            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                            resultJson.put("code", 1);
                            resultJson.put("message", "缺少公众号ID参数");
                            out.write(resultJson.toString());
                            return;
                        }

                        logger.info("单公众号发布请求 - 公众号ID: {}, 文档数量: {}", officialAccountId, documentsArray.length());

                        // 如果只有一个文档，使用单文档单账号发布任务类型
                        if (documentsArray.length() == 1) {
                            JSONObject docObj = documentsArray.getJSONObject(0);
                            int documentId = docObj.getInt("id");

                            Map<String, Object> taskData = new HashMap<>();
                            taskData.put("taskType", "SINGLE_DOC_SINGLE_ACCOUNT");
                            taskData.put("documentId", documentId);
                            taskData.put("accountId", officialAccountId);

                            String taskId = publishProducer.sendPublishTask(taskData);

                            logger.info("单文档单公众号发布任务已加入队列，任务ID: {}", taskId);

                            response.setStatus(HttpServletResponse.SC_OK);
                            resultJson.put("code", 0);
                            resultJson.put("message", "发布任务已成功加入队列，系统将异步处理，请稍后查看结果");
                            resultJson.put("taskId", taskId);
                        } else {
                            // 多文档单账号，使用多文档多账号模式但只传一个账号
                            JSONArray singleAccountArray = new JSONArray();
                            singleAccountArray.put(officialAccountId);

                            Map<String, Object> taskData = new HashMap<>();
                            taskData.put("taskType", "MULTIPLE_DOCS_MULTIPLE_ACCOUNTS");
                            taskData.put("documents", documentsArray);
                            taskData.put("accountIds", singleAccountArray);

                            String taskId = publishProducer.sendPublishTask(taskData);

                            logger.info("多文档单公众号发布任务已加入队列，任务ID: {}", taskId);

                            response.setStatus(HttpServletResponse.SC_OK);
                            resultJson.put("code", 0);
                            resultJson.put("message", "发布任务已成功加入队列，系统将异步处理，请稍后查看结果");
                            resultJson.put("taskId", taskId);
                        }
                    }

                } catch (Exception e) {
                    logger.error("处理批量发布到公众号请求异常: {}", e.getMessage(), e);
                    response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                    resultJson.put("code", 4);
                    resultJson.put("message", "服务器内部错误: " + e.getMessage());
                }
            }
            // 处理创建草稿请求
            else if (pathInfo != null && pathInfo.matches("^/\\d+/create-draft$")) {
                // 提取文档ID
                String[] parts = pathInfo.split("/");
                if (parts.length < 3) {
                    response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                    resultJson.put("code", 1);
                    resultJson.put("message", "请求路径格式不正确");
                    out.write(resultJson.toString());
                    return;
                }

                int documentId = Integer.parseInt(parts[1]);

                // 创建草稿
                String mediaId = createDraftToWechat(request, documentId);

                if (mediaId != null) {
                    response.setStatus(HttpServletResponse.SC_OK);
                    resultJson.put("code", 0);
                    resultJson.put("message", "创建草稿成功");
                    resultJson.put("media_id", mediaId);
                } else {
                    response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                    resultJson.put("code", 2);
                    resultJson.put("message", "创建草稿失败");
                }
            }
            // 处理发布草稿请求
            else if (pathInfo != null && pathInfo.equals("/publish-draft")) {
                // 获取media_id参数
                String mediaId = request.getParameter("media_id");
                if (mediaId == null || mediaId.isEmpty()) {
                    response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                    resultJson.put("code", 1);
                    resultJson.put("message", "缺少media_id参数");
                    out.write(resultJson.toString());
                    return;
                }

                // 发布草稿
                boolean success = publishDraftFromMediaId(request, mediaId);

                if (success) {
                    response.setStatus(HttpServletResponse.SC_OK);
                    resultJson.put("code", 0);
                    resultJson.put("message", "发布草稿成功");
                } else {
                    response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                    resultJson.put("code", 2);
                    resultJson.put("message", "发布草稿失败");
                }
            }
            // 处理公众号编辑请求
            else if (pathInfo != null && pathInfo.matches("^/wechat/accounts/\\d+$")
                    || pathInfo != null && pathInfo.startsWith("/wechat/accounts/")) {
                try {
                    logger.info("接收到公众号编辑请求");

                    // 提取公众号ID
                    String[] parts = pathInfo.split("/");
                    String accountId = parts[3];

                    // 从请求体获取JSON数据
                    BufferedReader reader = request.getReader();
                    StringBuilder sb = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        sb.append(line);
                    }
                    String requestBody = sb.toString();
                    logger.debug("公众号编辑请求体内容: {}", requestBody);

                    JSONObject jsonBody = new JSONObject(requestBody);
                    String accountName = jsonBody.getString("accountName");
                    String secretKey = jsonBody.getString("secretKey");

                    logger.info("接收到的编辑信息 - 公众号ID: {}, 名称: {}", accountId, accountName);

                    // 验证参数
                    if (accountName == null || accountName.isEmpty()) {
                        logger.warn("参数验证失败: 公众号名称不能为空");
                        response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                        resultJson.put("code", 1);
                        resultJson.put("message", "公众号名称不能为空");
                        out.write(resultJson.toString());
                        return;
                    }

                    // 从会话中获取当前登录用户的user_id
                    HttpSession session = request.getSession(false);
                    Integer userId = null;
                    if (session != null) {
                        userId = (Integer) session.getAttribute("userId");
                    }

                    if (userId == null) {
                        logger.warn("用户未登录，无法编辑公众号");
                        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                        resultJson.put("code", 5);
                        resultJson.put("message", "请先登录");
                        out.write(resultJson.toString());
                        return;
                    }

                    // 执行更新操作
                    boolean updated = updateWechatAccount(accountId, accountName, secretKey, userId);

                    if (updated) {
                        logger.info("公众号更新成功: ID={}, 名称={}", accountId, accountName);
                        response.setStatus(HttpServletResponse.SC_OK);
                        resultJson.put("code", 0);
                        resultJson.put("message", "公众号信息更新成功");
                    } else {
                        logger.error("公众号更新失败: ID={}", accountId);
                        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                        resultJson.put("code", 3);
                        resultJson.put("message", "公众号更新失败");
                    }
                } catch (Exception e) {
                    logger.error("处理公众号编辑请求异常: {}", e.getMessage(), e);
                    response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                    resultJson.put("code", 4);
                    resultJson.put("message", "服务器内部错误: " + e.getMessage());
                }
            }
            // 处理手动添加公众号请求
            else if (pathInfo != null && pathInfo.equals("/wechat/add-manual-account")) {
                try {
                    logger.info("接收到手动添加公众号请求");

                    // 从请求体获取JSON数据
                    BufferedReader reader = request.getReader();
                    StringBuilder sb = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        sb.append(line);
                    }
                    String requestBody = sb.toString();
                    logger.debug("请求体内容: {}", requestBody);

                    JSONObject jsonBody = new JSONObject(requestBody);

                    // 获取公众号信息
                    String accountName = jsonBody.getString("accountName");
                    String appId = jsonBody.getString("appId");
                    String appSecret = jsonBody.getString("appSecret");

                    logger.info("接收到的公众号信息 - 名称: {}, AppID: {}", accountName, appId);

                    // 验证参数
                    if (accountName == null || accountName.isEmpty() ||
                            appId == null || appId.isEmpty() ||
                            appSecret == null || appSecret.isEmpty()) {
                        logger.warn("参数验证失败: 缺少必要参数");
                        response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                        resultJson.put("code", 1);
                        resultJson.put("message", "参数不完整");
                        out.write(resultJson.toString());
                        return;
                    }

                    // 从会话中获取当前登录用户的user_id
                    HttpSession session = request.getSession(false);
                    Integer userId = null;
                    if (session != null) {
                        userId = (Integer) session.getAttribute("userId");
                    }

                    logger.debug("获取到的用户ID: {}", userId);

                    // 检查用户是否已登录
                    if (userId == null) {
                        logger.warn("用户未登录，无法添加公众号");
                        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                        resultJson.put("code", 5);
                        resultJson.put("message", "请先登录");
                        out.write(resultJson.toString());
                        return;
                    }

                    // 检查当前用户是否已经关联了该appid的公众号
                    logger.debug("检查用户ID: {} 是否已经关联了appid: {} 的公众号", userId, appId);
                    boolean isUserRelationExists = isUserAccountRelationExists(userId, appId);
                    if (isUserRelationExists) {
                        logger.warn("用户ID: {} 已经关联了appid: {} 的公众号", userId, appId);
                        response.setStatus(HttpServletResponse.SC_CONFLICT);
                        resultJson.put("code", 2);
                        resultJson.put("message", "您已经添加了该公众号");
                        out.write(resultJson.toString());
                        return;
                    }

                    // 添加公众号到数据库
                    logger.info("开始添加公众号到数据库: {}, {}", accountName, appId);
                    boolean added = addWechatAccountManually(accountName, appId, appSecret, userId);
                    if (added) {
                        logger.info("公众号添加成功: {}, {}", accountName, appId);
                        response.setStatus(HttpServletResponse.SC_OK);
                        resultJson.put("code", 0);
                        resultJson.put("message", "添加公众号成功");
                    } else {
                        logger.error("公众号添加失败: {}, {}", accountName, appId);
                        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                        resultJson.put("code", 3);
                        resultJson.put("message", "添加公众号失败");
                    }

                    logger.debug("手动添加公众号请求处理结果: {}", resultJson.toString());
                } catch (Exception e) {
                    logger.error("处理手动添加公众号请求异常: {}", e.getMessage(), e);
                    response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                    resultJson.put("code", 4);
                    resultJson.put("message", "服务器内部错误");
                }
            } else {
                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
                resultJson.put("code", 3);
                resultJson.put("message", "请求的资源不存在");
            }
        } catch (NumberFormatException e) {
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            resultJson.put("code", 1);
            resultJson.put("message", "无效的文档ID格式");
            logger.error("无效的文档ID格式", e);
        } catch (Exception e) {
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            resultJson.put("code", 2);
            resultJson.put("message", "服务器内部错误");
            logger.error("处理POST请求失败", e);
        } finally {
            out.write(resultJson.toString());
            out.flush();
            out.close();
        }
    }

    /**
     * 处理PUT请求 - 发布或撤销发布文档
     */
    @Override
    protected void doPut(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter out = response.getWriter();
        JSONObject resultJson = new JSONObject();

        try {
            String pathInfo = request.getPathInfo();
            if (pathInfo == null || pathInfo.equals("/")) {
                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                resultJson.put("code", 1);
                resultJson.put("message", "请求路径无效");
                out.write(resultJson.toString());
                return;
            }

            // 解析路径，格式：/documentId/action
            String[] parts = pathInfo.split("/");
            if (parts.length < 3) {
                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                resultJson.put("code", 1);
                resultJson.put("message", "请求路径格式不正确");
                out.write(resultJson.toString());
                return;
            }

            int documentId = Integer.parseInt(parts[1]);
            String action = parts[2];

            // 根据操作更新文档状态
            if (action.equals("publish")) {
                updateDocumentStatus(request, documentId, 1); // 发布：status=1
            } else if (action.equals("unpublish")) {
                updateDocumentStatus(request, documentId, 0); // 撤销发布：status=0
            } else {
                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                resultJson.put("code", 1);
                resultJson.put("message", "无效的操作类型");
                out.write(resultJson.toString());
                return;
            }

            response.setStatus(HttpServletResponse.SC_OK);
            resultJson.put("code", 0);
            resultJson.put("message", "操作成功");
        } catch (NumberFormatException e) {
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            resultJson.put("code", 1);
            resultJson.put("message", "无效的文档ID格式");
            logger.error("无效的文档ID格式", e);
        } catch (Exception e) {
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            resultJson.put("code", 2);
            resultJson.put("message", "服务器内部错误");
            logger.error("更新文档状态失败", e);
        } finally {
            out.write(resultJson.toString());
            out.flush();
            out.close();
        }
    }

    /**
     * 更新公众号信息
     */
    private boolean updateWechatAccount(String accountId, String accountName, String secretKey, int userId) {
        Connection conn = null;
        PreparedStatement pstmt = null;

        try {
            conn = new DatabaseUtil().getConnection();

            // 更新公众号信息到wechat_official_account表
            String updateSql = "UPDATE wechat_official_account SET account_name = ?";
            if (secretKey != null && !secretKey.isEmpty()) {
                updateSql += ", app_secret = ?";
            }
            updateSql += " WHERE id = ?";

            pstmt = conn.prepareStatement(updateSql);
            pstmt.setString(1, accountName);
            int paramIndex = 2;

            if (secretKey != null && !secretKey.isEmpty()) {
                pstmt.setString(paramIndex++, secretKey);
            }
            pstmt.setString(paramIndex, accountId);

            int rows = pstmt.executeUpdate();

            // 如果更新了至少一行，则认为更新成功
            return rows > 0;
        } catch (Exception e) {
            logger.error("更新公众号信息失败: {}", e.getMessage(), e);
            return false;
        } finally {
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                }
            }
        }
    }

    /**
     * 单个删除文档
     */
    private void deleteDocument(HttpServletRequest request, int documentId) throws SQLException {
        Connection conn = null;
        PreparedStatement pstmt = null;

        try {
            conn = DatabaseUtil.getConnection();
            // 从会话中获取当前登录用户的user_id
            Integer userId = (Integer) request.getSession().getAttribute("userId");
            if (userId == null) {
                userId = 0; // 默认值，确保SQL不会出错
            }
            String sql = "DELETE FROM wk_wenku WHERE id = ? AND user_id = ?";
            pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, documentId);
            // 只有当userId大于0时才设置第二个参数
            if (userId > 0) {
                pstmt.setInt(2, userId);
            }

            int affectedRows = pstmt.executeUpdate();
            logger.info("删除文档ID: {}, 影响行数: {}", documentId, affectedRows);
        } finally {
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    logger.error("关闭PreparedStatement失败", e);
                }
            }
            DatabaseUtil.closeConnection(conn);
        }
    }

    /**
     * 批量删除文档
     */
    private void batchDeleteDocuments(HttpServletRequest request, List<Integer> ids) throws SQLException {
        Connection conn = null;
        PreparedStatement pstmt = null;

        try {
            conn = DatabaseUtil.getConnection();
            // 开始事务
            conn.setAutoCommit(false);

            // 从会话中获取当前登录用户的user_id
            Integer userId = (Integer) request.getSession().getAttribute("userId");
            if (userId == null) {
                userId = 0; // 默认值，确保SQL不会出错
            }
            // 使用批量删除
            String sql = "DELETE FROM wk_wenku WHERE id = ? AND user_id = ?";
            pstmt = conn.prepareStatement(sql);

            for (Integer id : ids) {
                pstmt.setInt(1, id);
                pstmt.setInt(2, userId);
                pstmt.addBatch();
            }

            // 执行批量操作
            int[] affectedRows = pstmt.executeBatch();

            // 提交事务
            conn.commit();

            logger.info("批量删除文档，影响行数: {}", affectedRows.length);
        } catch (SQLException e) {
            // 回滚事务
            if (conn != null) {
                try {
                    conn.rollback();
                } catch (SQLException ex) {
                    logger.error("回滚事务失败", ex);
                }
            }
            throw e;
        } finally {
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    logger.error("关闭PreparedStatement失败", e);
                }
            }
            if (conn != null) {
                try {
                    conn.setAutoCommit(true); // 恢复默认设置
                    conn.close();
                } catch (SQLException e) {
                    logger.error("关闭Connection失败", e);
                }
            }
        }
    }

    /**
     * 根据ID获取单个文档信息
     */
    private Document getDocumentById(HttpServletRequest request, int documentId) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        Document doc = null;

        try {
            conn = DatabaseUtil.getConnection();
            Integer userId = 0; // 默认值

            // 处理request可能为null的情况（例如从消息队列调用时）
            if (request != null && request.getSession() != null) {
                userId = (Integer) request.getSession().getAttribute("userId");
                if (userId == null) {
                    userId = 0; // 默认值，确保SQL不会出错
                }
            }

            // 在消息队列消费环境中，我们可能不需要用户ID过滤
            String sql = "SELECT w.*, f.file_url, f.file_ext, f.file_size FROM wk_wenku w LEFT JOIN wk_file f ON w.file_id = f.file_id WHERE w.id = ?";
            if (userId > 0) {
                sql += " AND w.user_id = ?";
            }
            pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, documentId);
            // 只有当userId大于0时才设置第二个参数，与SQL语句构建逻辑保持一致
            if (userId > 0) {
                pstmt.setInt(2, userId);
            }

            rs = pstmt.executeQuery();
            if (rs.next()) {
                doc = new Document();
                doc.setId(rs.getInt("id"));
                doc.setTitle(rs.getString("title"));
                // 动态设置用户名
                doc.setUsername(userId != null ? "user_" + userId : "user_0");
                doc.setFileUrl(rs.getString("file_url"));
                doc.setStatus(rs.getInt("status"));
                doc.setWenType(rs.getString("wen_type"));

                try {
                    String fileExt = rs.getString("file_ext");
                    doc.setFileExt(fileExt);
                } catch (SQLException e) {
                    doc.setFileExt("");
                }

                try {
                    long fileSize = rs.getLong("file_size");
                    doc.setFileSize(fileSize);
                } catch (SQLException e) {
                    doc.setFileSize(0);
                }

                // 获取type_id字段
                try {
                    int typeId = rs.getInt("type_id");
                    doc.setTypeId(typeId);

                    // 根据type_id设置分类名称
                    switch (typeId) {
                        case 1:
                            doc.setCategory("创业");
                            break;
                        case 2:
                            doc.setCategory("战略管理");
                            break;
                        case 7:
                            doc.setCategory("数字化");
                            break;
                        case 8:
                            doc.setCategory("智慧城市/工业");
                            break;
                        case 9:
                            doc.setCategory("元宇宙/WEB3");
                            break;
                        case 13:
                            doc.setCategory("团队管理");
                            break;
                        case 14:
                            doc.setCategory("研发管理");
                            break;
                        case 15:
                            doc.setCategory("项目管理");
                            break;
                        case 18:
                            doc.setCategory("数据治理");
                            break;
                        case 19:
                            doc.setCategory("数字化转型");
                            break;
                        case 20:
                            doc.setCategory("大数据/中台");
                            break;
                        case 22:
                            doc.setCategory("职场思维");
                            break;
                        case 23:
                            doc.setCategory("流程与规范");
                            break;
                        case 24:
                            doc.setCategory("人工智能");
                            break;
                        case 25:
                            doc.setCategory("绩效管理");
                            break;
                        case 26:
                            doc.setCategory("架构设计/实践");
                            break;
                        case 27:
                            doc.setCategory("模板范本");
                            break;
                        case 28:
                            doc.setCategory("投融资");
                            break;
                        case 29:
                            doc.setCategory("合同范本");
                            break;
                        case 30:
                            doc.setCategory("软件开发");
                            break;
                        case 31:
                            doc.setCategory("面试题");
                            break;
                        case 32:
                            doc.setCategory("人力资源");
                            break;
                        case 33:
                            doc.setCategory("公司与股权");
                            break;
                        case 34:
                            doc.setCategory("技术前瞻");
                            break;
                        case 35:
                            doc.setCategory("商业计划书");
                            break;
                        case 36:
                            doc.setCategory("数字孪生");
                            break;
                        case 37:
                            doc.setCategory("干部与人才");
                            break;
                        case 38:
                            doc.setCategory("入党申请");
                            break;
                        case 39:
                            doc.setCategory("教育行业");
                            break;
                        case 40:
                            doc.setCategory("基础教育");
                            break;
                        case 41:
                            doc.setCategory("职场必备");
                            break;
                        case 42:
                            doc.setCategory("逻辑排版");
                            break;
                        case 43:
                            doc.setCategory("RPA/机器人");
                            break;
                        case 44:
                            doc.setCategory("销售与培训");
                            break;
                        case 45:
                            doc.setCategory("年终终结");
                            break;
                        case 46:
                            doc.setCategory("实时计算");
                            break;
                        case 47:
                            doc.setCategory("开发规范");
                            break;
                        case 48:
                            doc.setCategory("数据埋点");
                            break;
                        case 49:
                            doc.setCategory("信息与安全");
                            break;
                        case 50:
                            doc.setCategory("算法");
                            break;
                        case 51:
                            doc.setCategory("政策文件");
                            break;
                        case 52:
                            doc.setCategory("数据库");
                            break;
                        case 53:
                            doc.setCategory("芯产业");
                            break;
                        case 54:
                            doc.setCategory("产业洞察");
                            break;
                        case 55:
                            doc.setCategory("芯片制造");
                            break;
                        case 56:
                            doc.setCategory("质量管理");
                            break;
                        case 57:
                            doc.setCategory("画像/推荐系统");
                            break;
                        case 59:
                            doc.setCategory("云计算/云原生");
                            break;
                        case 60:
                            doc.setCategory("市场调研");
                            break;
                        case 61:
                            doc.setCategory("DEVPOS/运维");
                            break;
                        case 62:
                            doc.setCategory("大学教育");
                            break;
                        case 63:
                            doc.setCategory("办公技巧");
                            break;
                        case 64:
                            doc.setCategory("财务/税务");
                            break;
                        case 66:
                            doc.setCategory("linux");
                            break;
                        case 67:
                            doc.setCategory("企业架构与经营");
                            break;
                        case 68:
                            doc.setCategory("供应链/物流");
                            break;
                        case 69:
                            doc.setCategory("智慧农业");
                            break;
                        case 70:
                            doc.setCategory("边缘/隐私计算");
                            break;
                        case 71:
                            doc.setCategory("前端");
                            break;
                        case 72:
                            doc.setCategory("安防监控");
                            break;
                        case 73:
                            doc.setCategory("汽车产业");
                            break;
                        case 74:
                            doc.setCategory("医疗健康");
                            break;
                        case 75:
                            doc.setCategory("卫星与通信");
                            break;
                        case 76:
                            doc.setCategory("操作系统");
                            break;
                        case 77:
                            doc.setCategory("金融银行");
                            break;
                        case 78:
                            doc.setCategory("物联网");
                            break;
                        case 79:
                            doc.setCategory("思维模型");
                            break;
                        case 80:
                            doc.setCategory("PPT模板");
                            break;
                        case 81:
                            doc.setCategory("简历模板");
                            break;
                        case 82:
                            doc.setCategory("述职报告");
                            break;
                        case 83:
                            doc.setCategory("搜索引擎");
                            break;
                        case 84:
                            doc.setCategory("公务员教育");
                            break;
                        case 85:
                            doc.setCategory("产品设计");
                            break;
                        case 86:
                            doc.setCategory("行业模板");
                            break;
                        case 87:
                            doc.setCategory("游戏");
                            break;
                        case 88:
                            doc.setCategory("新能源");
                            break;
                        case 89:
                            doc.setCategory("招投标");
                            break;
                        case 90:
                            doc.setCategory("面试题");
                            break;
                        case 91:
                            doc.setCategory("数据库");
                            break;
                        default:
                            doc.setCategory("默认分类");
                    }
                } catch (SQLException e) {
                    doc.setTypeId(0);
                    doc.setCategory("默认分类");
                }

                // 尝试不同的可能的价格列名
                try {
                    doc.setPrice(rs.getBigDecimal("file_jine"));
                } catch (SQLException e) {
                    try {
                        doc.setPrice(rs.getBigDecimal("price"));
                    } catch (SQLException ex) {
                        doc.setPrice(null);
                    }
                }
            }
        } catch (SQLException e) {
            logger.error("查询单个文档失败: {}", e.getMessage());
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    logger.error("关闭ResultSet失败", e);
                }
            }
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    logger.error("关闭PreparedStatement失败", e);
                }
            }
            DatabaseUtil.closeConnection(conn);
        }

        return doc;
    }

    /**
     * 通过wen_id从wk_file_png表中获取图片URL列表
     */
    private List<String> getImageUrlsByWenId(int wenId) {
        List<String> imageUrls = new ArrayList<>();
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try {
            conn = DatabaseUtil.getConnection();
            if (conn != null) {
                // 查询wk_file_png表获取图片URL
                String sql = "SELECT url FROM wk_file_png WHERE wen_id = ?";
                logger.info("执行SQL查询: {}", sql);
                pstmt = conn.prepareStatement(sql);
                pstmt.setInt(1, wenId);
                rs = pstmt.executeQuery();

                int count = 0;
                while (rs.next()) {
                    count++;
                    String fileUrl = rs.getString("url");
                    if (fileUrl != null && !fileUrl.isEmpty()) {
                        imageUrls.add(fileUrl);
                    } else {
                    }
                }
                logger.info("文档ID: {} 总共找到 {} 条图片记录，有效URL: {}", wenId, count, imageUrls.size());
            } else {
                logger.error("无法获取数据库连接");
            }
        } catch (SQLException e) {
            logger.error("从数据库获取图片URL失败: {}", e.getMessage(), e);
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    logger.error("关闭ResultSet失败", e);
                }
            }
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    logger.error("关闭PreparedStatement失败", e);
                }
            }
            if (conn != null) {
                DatabaseUtil.closeConnection(conn);
            }
        }

        return imageUrls;
    }

    /**
     * 发布文档到微信公众号（带详细状态信息）
     */
    public Map<String, Object> publishToWechatWithDetails(HttpServletRequest request, int documentId,
            String accountId) {
        Map<String, Object> result = new HashMap<>();
        result.put("success", false);
        result.put("draftCreated", false);
        result.put("message", "发布失败");

        try {
            // 获取文档信息
            Document doc = getDocumentById(request, documentId);
            if (doc == null) {
                logger.error("未找到文档ID: {}", documentId);
                result.put("message", "未找到文档");
                return result;
            }

            if (doc.getStatus() != 1) { // 只有已发布的文档才能发布到公众号
                logger.error("文档ID: {} 未发布，不能发布到公众号", documentId);
                result.put("message", "文档未发布，不能发布到公众号");
                return result;
            }

            logger.info("开始发布文档到公众号，文档ID: {}, 标题: {}", documentId, doc.getTitle());

            // 微信公众号的AppID和AppSecret，默认初始化为null
            String appId = null;
            String appSecret = null;
            String refreshToken = null;
            String nickname = null;

            logger.info("publishToWechat方法接收到的参数 - documentId: {}, accountId: {}", documentId, accountId);

            // 如果提供了accountId，则从数据库中获取对应的AppID和AppSecret
            if (accountId != null && !accountId.isEmpty()) {
                logger.info("尝试从数据库获取公众号信息，accountId: {}", accountId);
                Map<String, String> accountInfo = getWechatAccountInfo(accountId);
                if (accountInfo != null) {
                    appId = accountInfo.get("appId");
                    appSecret = accountInfo.get("appSecret");
                    refreshToken = accountInfo.get("refreshToken");
                    nickname = accountInfo.get("nickname");
                    logger.info("成功获取公众号信息，appId: {}, 公众号名称: {}", appId, nickname);
                } else {
                    logger.warn("未找到对应的公众号信息，无法继续发布");
                    result.put("message", "未找到对应的公众号信息");
                    return result;
                }
            } else {
                logger.warn("未提供accountId，无法获取公众号信息，无法继续发布。accountId值: [{}]", accountId);
                result.put("message", "未提供公众号ID");
                return result;
            }

            // 验证获取到的公众号信息
            if (appId == null || appSecret == null) {
                logger.error("获取的公众号信息不完整，缺少appId或appSecret");
                result.put("message", "公众号信息不完整");
                return result;
            }

            // 1. 获取access_token
            String accessToken = getAccessToken(appId, appSecret);
            if (accessToken == null) {
                logger.error("获取微信公众号access_token失败");
                result.put("message", "获取访问令牌失败");
                return result;
            }

            // 2. 构建文章内容
            String articleTitle = doc.getTitle();

            // 尝试从文档URL读取实际内容
            String documentContent = "";
            // 只有当文档不是PDF或PPT格式时才获取实际内容
            boolean isPptOrPdf = doc.getFileExt() != null &&
                    (doc.getFileExt().toLowerCase().contains("pdf") ||
                            doc.getFileExt().toLowerCase().contains("ppt") ||
                            doc.getFileExt().toLowerCase().contains("pptx"));

            if (!isPptOrPdf) {
                documentContent = getDocumentContentFromUrl(doc.getFileUrl());
            } else {
                logger.info("文档ID: {} 是PPT/PDF类型，不读取实际内容", documentId);
            }

            // 构建文章内容
            StringBuilder articleContentBuilder = new StringBuilder();

            if (!documentContent.isEmpty()) {
                logger.info("成功获取文档内容，正在构建文章");
                // 直接使用文档内容，不添加额外前缀
                articleContentBuilder.append(documentContent);
            } else {
                logger.warn("无法获取文档内容，仅提供文档链接");
            }

            // 获取文档关联的图片URL列表
            List<String> imageUrls = getImageUrlsByWenId(documentId);
            if (imageUrls.isEmpty()) {
                logger.info("文档中没有找到图片URL");
            } else {
                logger.info("文档中找到 {} 个图片URL", imageUrls.size());
            }

            String articleContent = articleContentBuilder.toString();

            // 3. 创建草稿
            // 获取文档类型信息，优先使用wenType，如果为空则使用fileExt
            String documentType = doc.getWenType() != null ? doc.getWenType()
                    : (doc.getFileExt() != null ? doc.getFileExt() : "");
            String draftMediaId = createArticleDraft(accessToken, articleTitle, articleContent, documentId, imageUrls,
                    documentType);
            if (draftMediaId == null) {
                logger.error("创建草稿失败");
                result.put("message", "创建草稿失败");
                return result;
            }

            // 草稿创建成功
            result.put("draftCreated", true);
            result.put("mediaId", draftMediaId);
            result.put("success", true);
            result.put("message", "草稿创建成功！您可以在微信公众号后台查看并发布此草稿。");
            logger.info("草稿创建成功，media_id: {}", draftMediaId);
            logger.info("文档ID: {} 已成功创建草稿到公众号", documentId);

            return result;
        } catch (Exception e) {
            logger.error("发布到公众号过程中发生异常: {}", e.getMessage(), e);
            result.put("message", "发布过程中发生异常: " + e.getMessage());
            return result;
        }
    }

    /**
     * 发布文档到微信公众号（兼容旧代码）
     */
    private boolean publishToWechat(HttpServletRequest request, int documentId, String accountId) {
        try {
            // 获取文档信息
            Document doc = getDocumentById(request, documentId);
            if (doc == null) {
                logger.error("未找到文档ID: {}", documentId);
                return false;
            }

            if (doc.getStatus() != 1) { // 只有已发布的文档才能发布到公众号
                logger.error("文档ID: {} 未发布，不能发布到公众号", documentId);
                return false;
            }

            logger.info("开始发布文档到公众号，文档ID: {}, 标题: {}", documentId, doc.getTitle());

            // 微信公众号的AppID和AppSecret，默认初始化为null
            String appId = null;
            String appSecret = null;
            String refreshToken = null;
            String nickname = null;

            logger.info("publishToWechat方法接收到的参数 - documentId: {}, accountId: {}", documentId, accountId);

            // 如果提供了accountId，则从数据库中获取对应的AppID和AppSecret
            if (accountId != null && !accountId.isEmpty()) {
                logger.info("尝试从数据库获取公众号信息，accountId: {}", accountId);
                Map<String, String> accountInfo = getWechatAccountInfo(accountId);
                if (accountInfo != null) {
                    appId = accountInfo.get("appId");
                    appSecret = accountInfo.get("appSecret");
                    refreshToken = accountInfo.get("refreshToken");
                    nickname = accountInfo.get("nickname");
                    logger.info("成功获取公众号信息，appId: {}, 公众号名称: {}", appId, nickname);
                } else {
                    logger.warn("未找到对应的公众号信息，无法继续发布");
                    return false;
                }
            } else {
                logger.warn("未提供accountId，无法获取公众号信息，无法继续发布。accountId值: [{}]", accountId);
                return false;
            }

            // 验证获取到的公众号信息
            if (appId == null || appSecret == null) {
                logger.error("获取的公众号信息不完整，缺少appId或appSecret");
                return false;
            }

            // 1. 获取access_token
            String accessToken = null;
            if (refreshToken != null) {
                // 如果有refreshToken，使用开放平台授权流程获取access_token
                accessToken = getAuthorizerAccessToken(appId, refreshToken);
            }

            // 如果没有refreshToken或者通过refreshToken获取失败，则使用传统方式获取access_token
            if (accessToken == null && appSecret != null) {
                logger.info("使用appId和appSecret获取access_token");
                accessToken = getAccessToken(appId, appSecret);
            }

            if (accessToken == null) {
                logger.error("获取微信公众号access_token失败");
                return false;
            }

            // 2. 通过wen_id从wk_file_png获取图片URL列表
            List<String> imageUrls = getImageUrlsByWenId(documentId);
            logger.info("文档ID: {} 获取到的图片URL数量: {}", documentId, imageUrls.size());

            // 3. 构建文章内容
            String articleTitle = doc.getTitle();
            String articleContent = "这是从testUpload系统发布到微信公众号的文档：" + doc.getTitle() + "\n\n";
            articleContent += "文档分类：" + doc.getCategory() + "\n";
            articleContent += "文档类型：" + ("free".equals(doc.getWenType()) ? "免费" : "付费") + "\n";
            if (doc.getPrice() != null) {
                articleContent += "文档价格：" + doc.getPrice() + "\n";
            }

            // 添加图片URL信息
            if (!imageUrls.isEmpty()) {
                articleContent += "\n文档图片：";
                for (int i = 0; i < imageUrls.size(); i++) {
                    articleContent += "\n" + (i + 1) + ". " + imageUrls.get(i);
                }
            }

            // 3. 调用微信公众号API发布文章，传入图片URL列表
            boolean publishSuccess = publishArticleToWechat(accessToken, articleTitle, articleContent, documentId,
                    imageUrls);

            if (publishSuccess) {
                logger.info("文档ID: {} 发布到公众号成功", documentId);
                // 可以在这里添加记录发布日志的代码
                return true;
            } else {
                logger.error("文档ID: {} 发布到公众号失败", documentId);
                return false;
            }
        } catch (Exception e) {
            logger.error("发布到公众号过程中发生异常: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 通过开放平台授权获取公众号的access_token
     * 
     * @param authorizerAppid        授权方appid
     * @param authorizerRefreshToken 授权方的刷新令牌
     * @return access_token，如果失败则返回null
     */
    private String getAuthorizerAccessToken(String authorizerAppid, String authorizerRefreshToken) {
        try {
            logger.info("开始通过开放平台授权获取access_token，authorizerAppid: {}",
                    authorizerAppid.substring(0, 8) + "..."); // 仅显示部分appid，保护隐私

            // 获取第三方平台的component_access_token
            String componentAccessToken = getComponentAccessToken();
            if (componentAccessToken == null) {
                logger.error("获取component_access_token失败");
                return null;
            }

            // 微信开放平台获取authorizer_access_token的接口
            String url = "https://api.weixin.qq.com/cgi-bin/component/api_authorizer_token?component_access_token="
                    + componentAccessToken;

            // 构建请求JSON
            JSONObject requestJson = new JSONObject();
            requestJson.put("component_appid", getComponentAppid()); // 第三方平台appid
            requestJson.put("authorizer_appid", authorizerAppid);
            requestJson.put("authorizer_refresh_token", authorizerRefreshToken);

            // 发送POST请求
            String response = sendPostRequest(url, requestJson.toString());
            if (response == null || response.isEmpty()) {
                logger.error("获取authorizer_access_token响应为空");
                return null;
            }

            logger.info("收到获取authorizer_access_token响应: {}", response);

            // 解析JSON响应
            JSONObject jsonResponse = new JSONObject(response);

            // 检查是否有错误码
            if (jsonResponse.has("errcode") && jsonResponse.getInt("errcode") != 0) {
                int errcode = jsonResponse.getInt("errcode");
                String errmsg = jsonResponse.getString("errmsg");
                logger.error("微信API返回错误: errcode={}, errmsg={}", errcode, errmsg);
                return null;
            }

            if (jsonResponse.has("authorizer_access_token")) {
                String accessToken = jsonResponse.getString("authorizer_access_token");
                long expiresIn = jsonResponse.getLong("expires_in");
                logger.info("获取authorizer_access_token成功，有效期: {}秒", expiresIn);

                // 如果有新的authorizer_refresh_token，更新到数据库
                if (jsonResponse.has("authorizer_refresh_token")) {
                    String newRefreshToken = jsonResponse.getString("authorizer_refresh_token");
                    updateAuthorizerRefreshToken(authorizerAppid, newRefreshToken);
                }

                return accessToken;
            } else {
                logger.error("获取authorizer_access_token失败，响应中不包含authorizer_access_token: {}", response);
                return null;
            }
        } catch (Exception e) {
            logger.error("获取authorizer_access_token异常: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 获取第三方平台的component_access_token
     * 
     * @return component_access_token，如果失败则返回null
     */
    private String getComponentAccessToken() {
        try {
            logger.info("开始获取component_access_token");

            // 微信开放平台获取component_access_token的接口
            String url = "https://api.weixin.qq.com/cgi-bin/component/api_component_token";

            // 构建请求JSON
            JSONObject requestJson = new JSONObject();
            requestJson.put("component_appid", getComponentAppid()); // 第三方平台appid
            requestJson.put("component_appsecret", getComponentAppsecret()); // 第三方平台appsecret
            requestJson.put("component_verify_ticket", getComponentVerifyTicket()); // 平台推送的ticket

            // 发送POST请求
            String response = sendPostRequest(url, requestJson.toString());
            if (response == null || response.isEmpty()) {
                logger.error("获取component_access_token响应为空");
                return null;
            }

            logger.info("收到获取component_access_token响应: {}", response);

            // 解析JSON响应
            JSONObject jsonResponse = new JSONObject(response);

            // 检查是否有错误码
            if (jsonResponse.has("errcode") && jsonResponse.getInt("errcode") != 0) {
                int errcode = jsonResponse.getInt("errcode");
                String errmsg = jsonResponse.getString("errmsg");
                logger.error("微信API返回错误: errcode={}, errmsg={}", errcode, errmsg);
                return null;
            }

            if (jsonResponse.has("component_access_token")) {
                String componentAccessToken = jsonResponse.getString("component_access_token");
                long expiresIn = jsonResponse.getLong("expires_in");
                logger.info("获取component_access_token成功，有效期: {}秒", expiresIn);
                return componentAccessToken;
            } else {
                logger.error("获取component_access_token失败，响应中不包含component_access_token: {}", response);
                return null;
            }
        } catch (Exception e) {
            logger.error("获取component_access_token异常: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 更新数据库中的authorizer_refresh_token
     */
    private void updateAuthorizerRefreshToken(String authorizerAppid, String newRefreshToken) {
        // 检查参数有效性
        if (authorizerAppid == null || newRefreshToken == null ||
                authorizerAppid.isEmpty() || newRefreshToken.isEmpty()) {
            logger.error("更新authorizer_refresh_token参数无效");
            return;
        }
        Connection conn = null;
        PreparedStatement pstmt = null;

        try {
            conn = DatabaseUtil.getConnection();
            String sql = "UPDATE wechat_authorizers SET authorizer_refresh_token = ?, update_time = NOW() WHERE authorizer_appid = ?";
            pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, newRefreshToken);
            pstmt.setString(2, authorizerAppid);

            int rowsAffected = pstmt.executeUpdate();
            if (rowsAffected > 0) {
                logger.info("更新authorizer_refresh_token成功，authorizerAppid: {}",
                        authorizerAppid.substring(0, 8) + "...");
            } else {
                logger.warn("未找到对应的authorizerAppid，无法更新refresh_token: {}",
                        authorizerAppid.substring(0, 8) + "...");
            }
        } catch (Exception e) {
            logger.error("更新authorizer_refresh_token异常: {}", e.getMessage(), e);
        } finally {
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    logger.error("关闭PreparedStatement失败", e);
                }
            }
            DatabaseUtil.closeConnection(conn);
        }
    }

    /**
     * 创建草稿到微信公众号
     */
    private String createDraftToWechat(HttpServletRequest request, int documentId) {
        try {
            logger.info("开始创建草稿到微信公众号，文档ID: {}", documentId);

            // 获取文档信息
            Document doc = getDocumentById(request, documentId);
            if (doc == null) {
                logger.error("未找到文档ID: {}", documentId);
                return null;
            }

            // 从请求参数或会话中获取公众号ID
            String accountId = request.getParameter("accountId");
            if (accountId == null || accountId.isEmpty()) {
                // 尝试从会话中获取默认公众号ID
                accountId = (String) request.getSession().getAttribute("defaultWechatAccountId");
            }

            // 微信公众号的AppID和AppSecret，默认初始化为null
            String appId = null;
            String appSecret = null;

            // 如果提供了accountId，则从数据库中获取对应的AppID和AppSecret
            if (accountId != null && !accountId.isEmpty()) {
                logger.info("尝试从数据库获取公众号信息，accountId: {}", accountId);
                Map<String, String> accountInfo = getWechatAccountInfo(accountId);
                if (accountInfo != null) {
                    appId = accountInfo.get("appId");
                    appSecret = accountInfo.get("appSecret");
                }
            }

            // 验证公众号信息是否完整
            if (appId == null || appSecret == null || appId.isEmpty() || appSecret.isEmpty()) {
                logger.error("公众号信息不完整，appId: {}, appSecret: {}", appId, appSecret);
                return null;
            }

            // 1. 获取access_token
            String accessToken = getAccessToken(appId, appSecret);
            if (accessToken == null) {
                logger.error("获取微信公众号access_token失败");
                return null;
            }

            // 2. 通过wen_id从wk_file_png获取图片URL列表
            List<String> imageUrls = getImageUrlsByWenId(documentId);
            logger.info("创建草稿时，文档ID: {} 获取到的图片URL数量: {}", documentId, imageUrls.size());

            // 3. 构建文章内容
            String articleTitle = doc.getTitle();
            String articleContent = "这是从testUpload系统创建的草稿文档：" + doc.getTitle() + "\n\n";
            articleContent += "文档分类：" + doc.getCategory() + "\n";
            articleContent += "文档类型：" + ("free".equals(doc.getWenType()) ? "免费" : "付费") + "\n";
            if (doc.getPrice() != null) {
                articleContent += "文档价格：" + doc.getPrice() + "\n";
            }

            // 添加图片URL信息
            if (!imageUrls.isEmpty()) {
                articleContent += "\n文档图片：";
                for (int i = 0; i < imageUrls.size(); i++) {
                    articleContent += "\n" + (i + 1) + ". " + imageUrls.get(i);
                }
            }

            // 4. 创建文章草稿，传入图片URL列表
            // 获取文档类型信息
            String documentType = doc.getWenType() != null ? doc.getWenType()
                    : (doc.getFileExt() != null ? doc.getFileExt() : "");
            String mediaId = createArticleDraft(accessToken, articleTitle, articleContent, documentId, imageUrls,
                    documentType);

            if (mediaId != null) {
                logger.info("文章草稿创建成功，文档ID: {}, media_id: {}", documentId, mediaId);
            } else {
                logger.error("文章草稿创建失败，文档ID: {}", documentId);
            }

            return mediaId;
        } catch (Exception e) {
            logger.error("创建文章草稿过程中发生异常: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 根据media_id发布草稿
     */
    private boolean publishDraftFromMediaId(HttpServletRequest request, String mediaId) {
        try {
            logger.info("开始发布草稿，media_id: {}", mediaId);

            // 微信公众号的AppID和AppSecret，从数据库获取
            // 注意：在实际应用中，这里应该根据media_id关联到特定的公众号
            // 这里简化处理，获取默认或第一个公众号
            String appId = null;
            String appSecret = null;

            // 获取第一个可用的公众号信息
            logger.debug("获取可用的公众号列表");
            List<Map<String, Object>> accounts = getWechatAccounts(request);

            if (!accounts.isEmpty()) {
                logger.debug("找到可用的公众号数量: {}", accounts.size());
                Map<String, Object> firstAccount = accounts.get(0);
                appId = (String) firstAccount.get("authorizerAppid");
                logger.debug("选中的公众号AppID: {}", appId);

                // 需要从wechat_official_account表获取appSecret
                if (appId != null && !appId.isEmpty()) {
                    logger.debug("根据AppID获取公众号详情: {}", appId);
                    Map<String, String> accountInfo = getWechatAccountInfoByAppId(appId);
                    if (accountInfo != null) {
                        appSecret = accountInfo.get("appSecret");
                        logger.debug("成功获取公众号AppSecret");
                    } else {
                        logger.warn("未找到对应AppID的公众号详情: {}", appId);
                    }
                }
            } else {
                logger.warn("未找到任何可用的公众号");
            }

            // 验证公众号信息是否完整
            if (appId == null || appSecret == null || appId.isEmpty() || appSecret.isEmpty()) {
                logger.error("未找到有效的公众号信息");
                return false;
            }

            // 1. 获取access_token
            String accessToken = getAccessToken(appId, appSecret);
            if (accessToken == null) {
                logger.error("获取微信公众号access_token失败");
                return false;
            }

            // 2. 发布草稿
            boolean success = publishDraftToWechat(accessToken, mediaId);

            if (success) {
                logger.info("草稿发布成功，media_id: {}", mediaId);
            } else {
                logger.error("草稿发布失败，media_id: {}", mediaId);
            }

            return success;
        } catch (Exception e) {
            logger.error("发布草稿过程中发生异常: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 从数据库获取文档关联的文件URL
     */
    private String getFileUrlByDocumentId(int documentId) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        String fileUrl = null;

        try {
            conn = DatabaseUtil.getConnection();
            if (conn != null) {
                // 查询wk_wenku表获取file_id
                String wenkuSql = "SELECT file_id FROM wk_wenku WHERE id = ?";
                pstmt = conn.prepareStatement(wenkuSql);
                pstmt.setInt(1, documentId);
                rs = pstmt.executeQuery();

                int fileId = 0;
                if (rs.next()) {
                    fileId = rs.getInt("file_id");
                    logger.info("文档ID: {} 关联的file_id: {}", documentId, fileId);
                }

                // 关闭当前资源，准备查询wk_file表
                rs.close();
                pstmt.close();

                if (fileId > 0) {
                    // 查询wk_file表获取file_url
                    String fileSql = "SELECT file_url FROM wk_file WHERE file_id = ?";
                    pstmt = conn.prepareStatement(fileSql);
                    pstmt.setInt(1, fileId);
                    rs = pstmt.executeQuery();

                    if (rs.next()) {
                        fileUrl = rs.getString("file_url");
                        logger.info("file_id: {} 对应的file_url: {}", fileId, fileUrl);
                    }
                }
            }
        } catch (SQLException e) {
            logger.error("从数据库获取文件URL失败: {}", e.getMessage(), e);
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    logger.error("关闭ResultSet失败", e);
                }
            }
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    logger.error("关闭PreparedStatement失败", e);
                }
            }
            if (conn != null) {
                DatabaseUtil.closeConnection(conn);
            }
        }

        return fileUrl;
    }

    /**
     * 从文档URL读取内容
     */
    private String getDocumentContentFromUrl(String fileUrl) {
        if (fileUrl == null || fileUrl.isEmpty()) {
            logger.warn("文档URL为空，无法读取内容");
            return "";
        }

        StringBuilder content = new StringBuilder();
        try {
            URL url = new URL(fileUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(10000);
            connection.setReadTimeout(30000);
            connection.setRequestProperty("Accept", "*/*");
            connection.setRequestProperty("User-Agent", "Mozilla/5.0");

            logger.info("开始读取文档内容，URL: {}", fileUrl);

            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                try (BufferedReader reader = new BufferedReader(
                        new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        content.append(line).append("\n");
                    }
                }
                logger.info("成功读取文档内容，长度: {} 字符", content.length());

                // 如果是HTML或XML格式，尝试提取文本内容
                String contentType = connection.getContentType();
                if (contentType != null && (contentType.contains("html") || contentType.contains("xml"))) {
                    String textContent = extractTextFromHtml(content.toString());
                    if (!textContent.isEmpty()) {
                        return textContent;
                    }
                }

                return content.toString();
            } else {
                logger.error("读取文档内容失败，响应码: {}", responseCode);
            }
        } catch (Exception e) {
            logger.error("读取文档内容发生异常: {}", e.getMessage(), e);
        }
        return "";
    }

    /**
     * 从HTML中提取纯文本内容
     */
    private String extractTextFromHtml(String html) {
        try {
            if (html == null || html.isEmpty()) {
                return "";
            }

            // 更健壮的HTML标签移除，避免破坏内容结构
            // 使用非贪婪模式并转义特殊字符
            String noHtml = html.replaceAll("<script[^>]*?>.*?</script>", " ");
            noHtml = noHtml.replaceAll("<style[^>]*?>.*?</style>", " ");
            // 修改为更安全的正则表达式，避免未闭合字符类错误
            noHtml = noHtml.replaceAll("</?[^>]*>", " ");

            // 移除多余的空白字符和特殊的空白字符
            String cleanText = noHtml.replaceAll("\\s+", " ").trim();

            // 确保文本被正确编码
            return cleanText;
        } catch (Exception e) {
            logger.error("从HTML提取文本失败: {}", e.getMessage());
            // 如果正则表达式处理失败，使用更简单的方法
            try {
                // 使用更简单的字符替换方法
                StringBuilder sb = new StringBuilder();
                boolean inTag = false;
                for (char c : html.toCharArray()) {
                    if (c == '<') {
                        inTag = true;
                    } else if (c == '>') {
                        inTag = false;
                        sb.append(' ');
                    } else if (!inTag) {
                        sb.append(c);
                    }
                }
                return sb.toString().replaceAll("\\s+", " ").trim();
            } catch (Exception ex) {
                logger.error("备用HTML提取方法失败: {}", ex.getMessage());
                return html; // 如果所有方法都失败，返回原始内容
            }
        }
    }

    /**
     * HTML转义方法，处理特殊字符以避免JSON解析问题和显示乱码
     */
    private String escapeHtml(String input) {
        if (input == null) {
            return "";
        }

        StringBuffer sb = new StringBuffer(input.length());

        for (int i = 0; i < input.length(); i++) {
            char c = input.charAt(i);
            switch (c) {
                case '&':
                    sb.append("&amp;");
                    break;
                case '<':
                    sb.append("&lt;");
                    break;
                case '>':
                    sb.append("&gt;");
                    break;
                case '"':
                    sb.append("&quot;");
                    break;
                case '\'':
                    sb.append("&#039;");
                    break;
                case '\\':
                    sb.append("&#92;");
                    break;
                case '\t':
                    sb.append(" ");
                    break;
                default:
                    // 处理非ASCII字符，确保正确编码
                    if (c > 127) {
                        sb.append("&#").append((int) c).append("; ");
                    } else {
                        sb.append(c);
                    }
                    break;
            }
        }

        return sb.toString();
    }

    /**
     * 检查字符串是否包含特殊字符
     */
    private boolean containsSpecialCharacters(String input) {
        if (input == null) {
            return false;
        }

        // 检查是否包含常见的特殊字符，完全重写正则表达式以避免转义问题
        try {
            // 使用字符检查代替复杂的正则表达式
            for (char c : input.toCharArray()) {
                switch (c) {
                    case '&':
                    case '<':
                    case '>':
                    case '"':
                    case '\'':
                    case '\\':
                        return true;
                }
            }
            return false;
        } catch (Exception e) {
            logger.error("检查特殊字符时出错: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 从URL直接上传文件到微信公众号
     */
    private String uploadWechatMaterialFromUrl(String accessToken, String fileUrl, String type) {
        try {
            logger.info("准备从URL上传微信素材，URL: {}, 类型: {}", fileUrl, type);

            // 构建请求URL
            // 注意：对于素材上传API，需要将access_token作为URL参数传递
            String url = "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=" + accessToken
                    + "&type=" + type;
            logger.info("请求URL: {}", url);

            // 创建HTTP连接
            URL requestUrl = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) requestUrl.openConnection();
            conn.setRequestMethod("POST");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setConnectTimeout(10000);
            conn.setReadTimeout(10000);

            // 无需设置Authorization头，access_token已在URL中
            // 设置multipart/form-data请求
            String boundary = "----WebKitFormBoundary" + System.currentTimeMillis();
            conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);

            // 获取文件名
            String fileName = getFileNameFromUrl(fileUrl);
            if (fileName == null || fileName.isEmpty()) {
                // 根据类型设置更合适的默认文件名和扩展名
                String extension = ".jpg";
                if ("video".equals(type)) {
                    extension = ".mp4";
                } else if ("voice".equals(type)) {
                    extension = ".amr";
                }
                fileName = "temp_file_" + System.currentTimeMillis() + extension;
                logger.warn("无法从URL提取文件名，使用临时文件名: {}", fileName);
            }

            // 写入文件数据
            try (DataOutputStream out = new DataOutputStream(conn.getOutputStream())) {
                // 文件部分
                out.writeBytes("--" + boundary + "\r\n");
                out.writeBytes(
                        "Content-Disposition: form-data; name=\"media\"; filename=\"" + fileName + "\"\r\n");

                // 根据微信要求设置Content-Type
                String contentType = getContentType(fileName);

                // 对于微信公众号的特定类型，强制使用对应格式
                if ("image".equals(type)) {
                    // 微信图片素材要求使用正确的图片类型
                    if (fileName.toLowerCase().endsWith(".png")) {
                        contentType = "image/png";
                    } else if (fileName.toLowerCase().endsWith(".gif")) {
                        contentType = "image/gif";
                    } else if (fileName.toLowerCase().endsWith(".bmp")) {
                        contentType = "image/bmp";
                    } else {
                        // 默认使用jpeg格式
                        contentType = "image/jpeg";
                    }
                } else if ("video".equals(type)) {
                    contentType = "video/mp4";
                } else if ("voice".equals(type)) {
                    contentType = "audio/amr";
                }

                logger.info("使用Content-Type: {}, 文件名: {}", contentType, fileName);
                out.writeBytes("Content-Type: " + contentType + "\r\n");
                out.writeBytes("\r\n");

                // 直接从URL读取文件内容
                try (InputStream fileInputStream = new URL(fileUrl).openStream()) {
                    byte[] buffer = new byte[1024 * 4]; // 增大缓冲区提高效率
                    int bytesRead;
                    while ((bytesRead = fileInputStream.read(buffer)) != -1) {
                        out.write(buffer, 0, bytesRead);
                    }
                }

                out.writeBytes("\r\n");
                out.writeBytes("--" + boundary + "--\r\n");
                out.flush();
            }

            // 读取响应
            try (InputStream in = conn.getInputStream()) {
                byte[] buffer = new byte[1024];
                int len;
                StringBuilder sb = new StringBuilder();
                while ((len = in.read(buffer)) != -1) {
                    sb.append(new String(buffer, 0, len, StandardCharsets.UTF_8));
                }
                String response = sb.toString();
                logger.info("上传素材响应: {}", response);

                // 解析JSON响应
                JSONObject jsonResponse = new JSONObject(response);

                // 检查是否有错误码
                if (jsonResponse.has("errcode") && jsonResponse.getInt("errcode") != 0) {
                    int errcode = jsonResponse.getInt("errcode");
                    String errmsg = jsonResponse.getString("errmsg");
                    logger.error("上传素材失败: errcode={}, errmsg={}", errcode, errmsg);
                    return null;
                }

                // 提取media_id
                if (jsonResponse.has("media_id")) {
                    String mediaId = jsonResponse.getString("media_id");
                    logger.info("上传素材成功，media_id: {}", mediaId);
                    return mediaId;
                } else {
                    logger.error("上传素材成功但未返回media_id: {}", response);
                    return null;
                }
            }
        } catch (Exception e) {
            logger.error("从URL上传素材异常: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 从URL中提取文件名
     */
    private String getFileNameFromUrl(String url) {
        try {
            // 去除URL中的查询参数
            if (url.contains("?")) {
                url = url.substring(0, url.indexOf("?"));
            }
            // 获取最后一个斜杠后的部分作为文件名
            int lastSlashIndex = url.lastIndexOf('/');
            if (lastSlashIndex != -1 && lastSlashIndex < url.length() - 1) {
                return url.substring(lastSlashIndex + 1);
            }
        } catch (Exception e) {
            logger.error("从URL提取文件名失败: {}", e.getMessage(), e);
        }
        return null;
    }

    /**
     * 根据文件名获取Content-Type
     */
    private String getContentType(String fileName) {
        if (fileName == null || fileName.isEmpty()) {
            return "application/octet-stream";
        }

        // 转小写以便比较
        String lowerFileName = fileName.toLowerCase();

        // 微信公众号支持的图片类型
        if (lowerFileName.endsWith(".jpg")) {
            return "image/jpeg";
        } else if (lowerFileName.endsWith(".jpeg")) {
            return "image/jpeg";
        } else if (lowerFileName.endsWith(".png")) {
            return "image/png";
        } else if (lowerFileName.endsWith(".gif")) {
            return "image/gif";
        } else if (lowerFileName.endsWith(".bmp")) {
            return "image/bmp";
        }
        // 微信公众号支持的视频类型
        else if (lowerFileName.endsWith(".mp4")) {
            return "video/mp4";
        }
        // 微信公众号支持的音频类型
        else if (lowerFileName.endsWith(".amr")) {
            return "audio/amr";
        } else if (lowerFileName.endsWith(".mp3")) {
            return "audio/mpeg";
        }
        // 其他可能的文件类型
        else if (lowerFileName.endsWith(".pdf")) {
            return "application/pdf";
        } else if (lowerFileName.endsWith(".doc") || lowerFileName.endsWith(".docx")) {
            return "application/msword";
        } else if (lowerFileName.endsWith(".xls") || lowerFileName.endsWith(".xlsx")) {
            return "application/vnd.ms-excel";
        } else if (lowerFileName.endsWith(".ppt") || lowerFileName.endsWith(".pptx")) {
            return "application/vnd.ms-powerpoint";
        } else {
            // 默认使用application/octet-stream
            return "application/octet-stream";
        }
    }

    /**
     * 获取微信公众号的access_token
     */
    private String getAccessToken(String appId, String appSecret) {
        try {
            // 验证appId和appSecret的有效性
            if (appId == null || appId.isEmpty()) {
                logger.error("获取access_token失败：appId为空或无效");
                return null;
            }
            if (appSecret == null || appSecret.isEmpty()) {
                logger.error("获取access_token失败：appSecret为空或无效");
                return null;
            }

            // 微信公众号获取access_token的接口
            String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId
                    + "&secret=" + appSecret;

            logger.info("准备获取access_token，appId: {}", appId.length() > 8 ? appId.substring(0, 8) + "..." : appId);

            // 发送GET请求
            String response = sendGetRequest(url);
            if (response == null || response.isEmpty()) {
                logger.error("获取access_token响应为空");
                return null;
            }

            logger.info("获取access_token响应: {}", response);

            // 解析JSON响应
            JSONObject jsonResponse = new JSONObject(response);

            // 检查是否有错误码
            if (jsonResponse.has("errcode") && jsonResponse.getInt("errcode") != 0) {
                int errcode = jsonResponse.getInt("errcode");
                String errmsg = jsonResponse.getString("errmsg");
                logger.error("获取access_token失败，错误码: {}, 错误信息: {}", errcode, errmsg);

                // 特别处理常见错误
                if (errcode == 40164) {
                    // IP白名单错误
                    logger.error("IP白名单错误: 请在微信公众号平台添加当前服务器IP到白名单");
                    // 尝试从错误信息中提取IP地址
                    if (errmsg.contains("ip")) {
                        // 寻找IP地址的起始和结束位置（处理不同的错误消息格式）
                        int ipStartPos = errmsg.indexOf("ip") + 3;
                        int ipEndPos = errmsg.length();

                        // 查找第一个不是数字或点的字符作为结束位置
                        for (int i = ipStartPos; i < errmsg.length(); i++) {
                            char c = errmsg.charAt(i);
                            if (!Character.isDigit(c) && c != '.') {
                                ipEndPos = i;
                                break;
                            }
                        }

                        if (ipStartPos < ipEndPos) {
                            String ip = errmsg.substring(ipStartPos, ipEndPos);
                            logger.error("建议添加的IP地址: {}", ip);
                        }
                    }
                } else if (errcode == 40013) {
                    logger.error("appid无效，请检查配置");
                } else if (errcode == 40001) {
                    logger.error("appsecret无效，请检查配置");
                }
                return null;
            }

            if (jsonResponse.has("access_token")) {
                String accessToken = jsonResponse.getString("access_token");
                long expiresIn = jsonResponse.getLong("expires_in");
                logger.info("获取access_token成功，有效期: {}秒", expiresIn);
                return accessToken;
            } else {
                logger.error("获取access_token失败，响应中不包含access_token: {}", response);
                return null;
            }
        } catch (Exception e) {
            logger.error("获取access_token异常: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 调用微信公众号API创建文章草稿
     *
     * @return 草稿的media_id，如果失败则返回null
     */
    private String createArticleDraft(String accessToken, String title, String content, int documentId,
            List<String> imageUrls, String documentType) {
        try {
            logger.info("准备创建文章草稿，文档ID: {}, 标题: {}", documentId, title);

            // 移除测试图片URL的添加逻辑，只使用实际提供的关联图片
            logger.info("检查图片URL列表: {}",
                    imageUrls == null ? "null" : imageUrls.isEmpty() ? "empty" : String.join(", ", imageUrls));
            logger.info("使用的access_token: {}",
                    accessToken.substring(0, 10) + "..." + accessToken.substring(accessToken.length() - 10));

            String url = "https://api.weixin.qq.com/cgi-bin/draft/add?access_token=" + accessToken;
            logger.info("请求URL: {}", url.substring(0, url.indexOf("?access_token=") + 15) + "...");

            JSONObject requestJson = new JSONObject();
            JSONArray articlesArray = new JSONArray();
            JSONObject articleJson = new JSONObject();

            // 标题处理
            String processedTitle = title;
            // 预处理标题，替换特殊字符（中文引号等）为普通字符，避免Unicode转义问题
            if (processedTitle != null) {
                // 替换中文引号为普通引号
                processedTitle = processedTitle.replaceAll("[\\u201c\\u201d]", "\"");
                // 替换中文单引号为普通单引号
                processedTitle = processedTitle.replaceAll("[\\u2018\\u2019]", "'");
                // 替换其他可能导致问题的特殊字符
                processedTitle = processedTitle.replaceAll("\\u00A0", " "); // 替换非断行空格

                if (processedTitle.length() > 64) {
                    processedTitle = processedTitle.substring(0, 64);
                    logger.warn("文档ID: {} 标题过长已截断为64字符: {}", documentId, processedTitle);
                }
            }

            // 内容处理 - 根据文档类型决定是否包含原始内容
            // 对于PPT和PDF类型，只使用关联图片，不使用文档原始内容
            boolean isPptOrPdf = documentType != null
                    && (documentType.toLowerCase().contains("ppt") || documentType.toLowerCase().contains("pdf"));
            logger.info("文档类型判断：documentType={}, isPptOrPdf={}", documentType, isPptOrPdf);

            String processedContent = "";
            if (!isPptOrPdf && content != null) {
                // 非PPT和PDF类型，使用原始内容
                processedContent = content;
                logger.info("非PPT/PDF文档，使用原始文档内容");
            } else {
                // PPT和PDF类型，只使用图片，不使用原始内容
                logger.info("PPT/PDF文档，只使用关联图片，不包含原始文档内容");
            }

            // 添加文档关联的图片到文章正文中
            logger.info("检查imageUrls状态: imageUrls={}, isEmpty={}", imageUrls,
                    imageUrls == null ? true : imageUrls.isEmpty());
            StringBuilder imageContent = new StringBuilder();

            if (imageUrls != null && !imageUrls.isEmpty()) {
                logger.info("开始添加文档关联的图片到文章正文，总共 {} 张图片", imageUrls.size());
                // 输出所有图片URL用于调试
                logger.info("图片URL列表: {}", String.join(", ", imageUrls));

                for (int i = 0; i < imageUrls.size(); i++) {
                    String imageUrl = imageUrls.get(i);
                    try {
                        // 上传每张图片到微信服务器
                        logger.info("上传第{}张关联图片: {}", i + 1, imageUrl);
                        String wechatImageUrl = uploadWechatArticleImage(accessToken, imageUrl);
                        logger.info("图片上传结果: wechatImageUrl={}", wechatImageUrl);
                        if (wechatImageUrl != null && !wechatImageUrl.isEmpty()) {
                            // 确保URL被正确放入img标签中
                            logger.info("准备将微信URL添加到img标签: {}", wechatImageUrl);
                            String imgTag = "<p><img src=\"" + wechatImageUrl + "\" style=\"max-width: 100%;\"></p>";
                            logger.info("生成的img标签: {}", imgTag);
                            imageContent.append(imgTag);
                            logger.info("成功添加图片到文章正文，微信URL: {}", wechatImageUrl);
                        } else {
                            // 即使上传失败，也添加原始URL作为图片标签
                            logger.warn("上传图片失败或返回空URL，使用原始URL: {}", imageUrl);
                            String fallbackImgTag = "<p><img src=\"" + imageUrl
                                    + "\" style=\"max-width: 100%;\" alt=\"原始图片\"></p>";
                            logger.info("生成备用img标签: {}", fallbackImgTag);
                            imageContent.append(fallbackImgTag);
                        }
                        // 避免请求过于频繁
                        Thread.sleep(300);
                    } catch (Exception e) {
                        logger.error("处理图片时发生异常: {}", e.getMessage(), e);
                        // 异常情况下也添加备用图片标签
                        String exceptionImgTag = "<p><img src=\"https://via.placeholder.com/200\" style=\"max-width: 100%;\" alt=\"异常备用图片\"></p>";
                        logger.info("添加异常备用img标签: {}", exceptionImgTag);
                        imageContent.append(exceptionImgTag);
                    }
                }
            } else {
                logger.warn("没有找到文档关联的图片URL列表，仅使用测试图片标签");
            }

            // 将图片内容添加到文章正文
            logger.info("图片内容长度: {}, 是否为空: {}", imageContent.length(), imageContent.length() == 0);
            logger.info("准备将图片内容添加到文章正文，添加前正文长度: {}", processedContent.length());

            // 直接将图片内容添加到processedContent的开头，确保一定会被包含
            processedContent = imageContent.toString() + "\n\n" + processedContent;

            logger.info("添加图片内容后正文长度: {}", processedContent.length());
            // 检查添加后的内容是否包含img标签
            logger.info("添加图片内容后是否包含img标签: {}", processedContent.contains("<img"));
            // 输出处理后的内容前200个字符进行调试
            String processedContentPreview = processedContent.length() > 200
                    ? processedContent.substring(0, 200) + "..."
                    : processedContent;
            logger.info("处理后的内容预览: {}", processedContentPreview);

            // 不再调用processArticleImages方法，直接使用关联图片
            // processedContent = processArticleImages(processedContent, accessToken,
            // documentId);

            if (processedContent.length() > 200000) {
                processedContent = processedContent.substring(0, 200000);
                logger.warn("文档ID: {} 内容过长，已截断为200000字符", documentId);
            }

            // 封面图上传
            String thumbMediaId = null;
            try {
                if (imageUrls != null && !imageUrls.isEmpty()) {
                    String imageUrl = imageUrls.get(0);
                    logger.info("上传封面图: {}", imageUrl);
                    thumbMediaId = uploadWechatMaterialFromUrl(accessToken, imageUrl, "image");
                } else {
                    String defaultImageUrl = "https://static.didaproject.com/pdf/891f9b21c019f6b02f863aa9e934639b/file80.png";
                    thumbMediaId = uploadWechatMaterialFromUrl(accessToken, defaultImageUrl, "image");
                }
            } catch (Exception e) {
                logger.error("上传封面图失败: {}", e.getMessage(), e);
            }
            if (thumbMediaId == null) {
                logger.warn("未能上传封面图，使用默认thumb_media_id");
                thumbMediaId = "default_thumb_media_id";
            }

            // 构造文章JSON
            articleJson.put("title", processedTitle);

            // 在正文末尾添加文档详情页的二维码图片
            logger.info("==== 开始处理文档ID: {} 的二维码 ====", documentId);
            logger.info("在正文末尾添加文档详情页二维码，文档ID: {}", documentId);
            // 从配置中获取二维码域名，默认使用测试环境域名
            String currentEnv = EnvironmentManager.getInstance().getCurrentEnvironment();
            Properties config = EnvironmentManager.getInstance().getDatabaseConfig(currentEnv);
            String qrCodeDomain = config.getProperty("qrcodeDomain", "testdoc2.didaproject.com");
            String qrCodeUrl = "https://" + qrCodeDomain + "/wenku/" + documentId + ".html";
            logger.info("文档详情页URL: {}", qrCodeUrl);

            // 本地生成二维码图片
            logger.info("开始本地生成二维码图片");
            String localQrCodePath = null;
            try {
                // 使用ZXing库本地生成二维码
                // 创建项目内的保存路径
                String contextPath = getServletContext().getRealPath("/resources/qrcodes");
                File qrCodeDir = new File(contextPath);
                if (!qrCodeDir.exists()) {
                    qrCodeDir.mkdirs();
                    logger.info("创建二维码目录: {}", contextPath);
                }
                localQrCodePath = contextPath + File.separator + "qr_code_" + documentId + ".png";
                logger.info("本地二维码保存路径: {}", localQrCodePath);

                // ZXing二维码生成配置
                com.google.zxing.MultiFormatWriter writer = new com.google.zxing.MultiFormatWriter();
                com.google.zxing.BarcodeFormat format = com.google.zxing.BarcodeFormat.QR_CODE;
                int size = 300; // 二维码尺寸
                com.google.zxing.common.BitMatrix bitMatrix = writer.encode(
                        qrCodeUrl,
                        format,
                        size,
                        size,
                        new java.util.HashMap<com.google.zxing.EncodeHintType, Object>() {
                            {
                                put(com.google.zxing.EncodeHintType.CHARACTER_SET, "UTF-8");
                                put(com.google.zxing.EncodeHintType.ERROR_CORRECTION,
                                        com.google.zxing.qrcode.decoder.ErrorCorrectionLevel.H);
                                put(com.google.zxing.EncodeHintType.MARGIN, 1);
                            }
                        });

                // 将BitMatrix转换为图片并保存到本地文件
                com.google.zxing.client.j2se.MatrixToImageWriter.writeToPath(
                        bitMatrix,
                        "PNG",
                        java.nio.file.Paths.get(localQrCodePath));
                logger.info("二维码图片成功生成并保存到本地");
            } catch (Exception e) {
                logger.error("本地生成二维码图片失败: {}", e.getMessage(), e);
                // 异常处理：如果本地生成失败，使用备用方案
                logger.warn("使用备用方案：直接上传在线二维码");
                String qrCodeApiUrl = "https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=" + qrCodeUrl;
                localQrCodePath = qrCodeApiUrl;
            }

            // 先将本地生成的二维码上传到七牛云
            logger.info("先将本地生成的二维码上传到七牛云");
            String qiniuUrl = null;
            try {
                // 构建七牛云配置，使用Zone.autoZone自动选择最优区域
                com.qiniu.storage.Configuration cfg = new com.qiniu.storage.Configuration(
                        com.qiniu.common.Zone.autoZone());
                com.qiniu.storage.UploadManager uploadManager = new com.qiniu.storage.UploadManager(cfg);

                // 七牛云配置参数（复用自FileUploadServlet）
                String ACCESS_KEY = "vV_FGopUcLpPKwImUgDE8a2lCgTQjsdUqQmSpoa1";
                String SECRET_KEY = "w94IZ6dV899KrEqofAFwkagn0SSeZPPEXgaTj3Jr";
                String BUCKET_NAME = "project-yytimes";
                String DOMAIN = "static.didaproject.com";

                // 构建七牛云中的文件路径，使用wenku/qrcode前缀
                String key = "wenku/qrcode/qr_code_" + documentId + ".png";

                // 生成上传凭证
                com.qiniu.util.Auth auth = com.qiniu.util.Auth.create(ACCESS_KEY, SECRET_KEY);
                String upToken = auth.uploadToken(BUCKET_NAME, key);

                // 上传文件
                com.qiniu.http.Response response = uploadManager.put(localQrCodePath, key, upToken);

                // 解析上传结果
                if (response.isOK()) {
                    qiniuUrl = "https://" + DOMAIN + "/" + key;
                    logger.info("二维码成功上传到七牛云，URL: {}", qiniuUrl);
                }
            } catch (Exception e) {
                logger.error("上传二维码到七牛云失败: {}", e.getMessage(), e);
            }

            // 如果七牛云上传失败，仍然使用本地路径作为备用
            String imageUrlForWechat = qiniuUrl != null ? qiniuUrl : localQrCodePath;
            logger.info("最终用于上传到微信的图片URL: {}", imageUrlForWechat);

            // 上传图片到微信服务器
            logger.info("上传图片到微信服务器");
            String wechatImageUrl = null;
            String finalContent = processedContent; // 在外部作用域声明finalContent变量

            try {
                // 调用uploadWechatArticleImage方法上传图片到微信服务器
                wechatImageUrl = uploadWechatArticleImage(accessToken, imageUrlForWechat);
                logger.info("图片上传到微信服务器结果: wechatImageUrl={}", wechatImageUrl);

                // 如果上传失败，使用备用二维码图片
                if (wechatImageUrl == null || wechatImageUrl.isEmpty()) {
                    logger.warn("二维码图片上传到微信失败，使用备用二维码图片URL");
                    // 使用备用的通用二维码图片
                    wechatImageUrl = "https://mmbiz.qpic.cn/mmbiz_jpg/ciaqDnJprwv6l25XzJwibZQbJ8HM4FdF4d7V12ic6M82e3W9gAiaDZiaVicd9l6BZiaZiaFh9Vw/0?wx_fmt=jpeg";
                }

                // 使用微信服务器返回的图片URL构建二维码图片标签
                // 确保wechatImageUrl是HTTPS且不带参数
                String cleanWechatImageUrl = wechatImageUrl != null ? wechatImageUrl.replaceAll("`", "") : "";
                // 确保是HTTPS
                if (cleanWechatImageUrl.startsWith("http://")) {
                    cleanWechatImageUrl = cleanWechatImageUrl.replaceFirst("http://", "https://");
                }
                // 移除URL参数
                if (cleanWechatImageUrl.contains("?")) {
                    cleanWechatImageUrl = cleanWechatImageUrl.split("\\?")[0];
                }

                String cleanQrCodeUrl = qrCodeUrl != null ? qrCodeUrl.replaceAll("`", "") : "";

                String qrCodeImgTag = "<p><strong>扫描下载:</strong></p><p><img src=\"" + cleanWechatImageUrl
                        + "\" style=\"width:150px;height:150px;\"></p><p>文档详情页: " + cleanQrCodeUrl + "</p>";
                logger.info("构建的二维码图片标签: {}", qrCodeImgTag);

                // 移除误导性注释，确保二维码内容会被添加到文章中
                logger.info("准备将二维码内容添加到文章中");

                // 检查内容是否已经包含HTML标签
                boolean hasHtmlTags = processedContent.contains("<") && processedContent.contains(">");

                if (hasHtmlTags) {
                    // 如果已经包含HTML标签，直接使用，不做额外的段落格式化
                    logger.info("内容已包含HTML标签，直接使用");
                    finalContent = processedContent;
                } else {
                    // 如果没有HTML标签，进行段落格式化
                    logger.info("内容不包含HTML标签，进行段落格式化");
                    finalContent = "<p>" + processedContent.replace("\n", "</p><p>") + "</p>";
                }

                // 将二维码放在文章末尾
                logger.info("将二维码内容放在文章末尾");

                // 只使用p标签，不使用div标签
                String qrCodeImgTagFinal = "\n\n<p><strong>扫描下载:</strong></p>\n<p><img src=\""
                        + cleanWechatImageUrl + "\" style=\"width:150px;height:150px;\"></p>\n<p>文档详情页: "
                        + cleanQrCodeUrl + "</p>";

                // 直接将二维码添加到文章末尾
                finalContent = finalContent + qrCodeImgTagFinal;
                logger.info("二维码已添加到文章末尾");
                logger.info("finalContent中添加二维码后长度: {}", finalContent.length());

                // 记录完整的最终内容用于调试
                // 记录最终内容的截断版本，避免日志过大
                String contentPreview = finalContent.length() > 500
                        ? finalContent.substring(0, 500) + "...(剩余" + (finalContent.length() - 500) + "字符)"
                        : finalContent;
                logger.info("最终放入articleJson的content预览: {}", contentPreview);
                logger.info("内容中是否包含img标签: {}", finalContent.contains("<img"));
                // 检查最终内容是否包含二维码相关内容
                logger.info("最终内容是否包含二维码文字: {}", finalContent.contains("扫描下方二维码"));

                // 清理临时文件
                try {
                    if (localQrCodePath != null && !localQrCodePath.startsWith("http")) {
                        java.nio.file.Files.deleteIfExists(java.nio.file.Paths.get(localQrCodePath));
                        logger.info("成功删除临时二维码文件: {}", localQrCodePath);
                    }
                } catch (Exception e) {
                    logger.warn("删除临时二维码文件失败: {}", e.getMessage());
                }
            } catch (Exception e) {
                logger.error("处理二维码过程中发生错误: {}", e.getMessage(), e);
                // 继续执行，确保文档能正常创建，即使二维码处理失败
                // 如果发生异常，至少确保finalContent有一个基本值
                if (finalContent == null || finalContent.isEmpty()) {
                    finalContent = processedContent;
                }
            }

            articleJson.put("content", finalContent);
            articleJson.put("digest", processedTitle);
            articleJson.put("author", "嘀嗒文库");
            articleJson.put("thumb_media_id", thumbMediaId);
            articleJson.put("show_cover_pic", 0);
            articleJson.put("need_open_comment", 0);
            articleJson.put("only_fans_can_comment", 0);

            articlesArray.put(articleJson);
            requestJson.put("articles", articlesArray);

            String requestJsonPreview = requestJson.toString();
            if (requestJsonPreview.length() > 200)
                requestJsonPreview = requestJsonPreview.substring(0, 200) + "...";
            logger.info("构建请求参数完成: {}", requestJsonPreview);

            String response = sendPostRequest(url, requestJson.toString());
            logger.info("创建草稿响应: {}", response);

            if (response == null || response.isEmpty()) {
                logger.error("创建草稿响应为空");
                return null;
            }

            JSONObject jsonResponse = new JSONObject(response);
            if (jsonResponse.has("errcode") && jsonResponse.getInt("errcode") != 0) {
                int errcode = jsonResponse.getInt("errcode");
                String errmsg = jsonResponse.optString("errmsg");
                logger.error("微信API返回错误: errcode={}, errmsg={}", errcode, errmsg);
                return null;
            }

            String mediaId = jsonResponse.optString("media_id", null);
            if (mediaId != null) {
                logger.info("创建文章草稿成功，media_id: {}", mediaId);
                return mediaId;
            } else {
                logger.error("创建草稿失败，响应中不包含media_id: {}", response);
                return null;
            }

        } catch (Exception e) {
            logger.error("创建草稿异常: {}", e.getMessage(), e);
            return null;
        }
    }

    // 创建静态的HttpClient连接池实例
    private static final CloseableHttpClient HTTP_CLIENT;

    // 静态初始化块，配置HttpClient连接池
    static {
        // 创建连接管理器
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        // 设置最大连接数
        connectionManager.setMaxTotal(200);
        // 设置每个路由的最大连接数
        connectionManager.setDefaultMaxPerRoute(20);

        // 创建请求配置，设置超时时间 - 针对大文件上传增加超时时间
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(20000) // 连接超时时间增加到20秒
                .setSocketTimeout(120000) // 套接字超时时间增加到120秒（2分钟）
                .setConnectionRequestTimeout(10000) // 请求连接池超时时间10秒
                .build();

        // 创建HttpClient实例
        HTTP_CLIENT = HttpClients.custom()
                .setConnectionManager(connectionManager)
                .setDefaultRequestConfig(requestConfig)
                .build();
    }

    /**
     * 上传图文正文中的图片（uploadimg接口）
     */
    private String uploadWechatArticleImage(String accessToken, String imageUrl) {
        logger.info("开始上传图文图片: {}", imageUrl);

        // 定义重试次数
        int maxRetries = 3;
        int retryCount = 0;

        while (retryCount < maxRetries) {
            try {
                // 1. 下载图片到临时文件
                logger.info("步骤1: 下载图片到临时文件，重试次数: {}", retryCount);
                File tempFile = null;
                try {
                    tempFile = downloadFile(imageUrl);
                    if (tempFile == null) {
                        logger.error("下载图片失败: {}", imageUrl);
                        return null;
                    }
                    logger.info("临时文件下载成功，文件大小: {}KB", tempFile.length() / 1024);

                    // 2. 准备上传请求
                    logger.info("步骤2: 准备上传请求");
                    String uploadUrl = "https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token=" +
                            (accessToken.length() > 20 ? accessToken.substring(0, 20) + "..." : accessToken);
                    logger.info("上传URL: {}", uploadUrl);

                    HttpPost post = new HttpPost(
                            "https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token=" + accessToken);

                    // 大文件上传优化：设置请求头，增加缓冲区大小
                    MultipartEntityBuilder builder = MultipartEntityBuilder.create()
                            .setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
                            .addBinaryBody("media", tempFile);

                    post.setEntity(builder.build());
                    logger.info("请求实体构建完成");

                    // 3. 执行上传请求（使用连接池中的HttpClient）
                    logger.info("步骤3: 执行上传请求到微信服务器");
                    try (CloseableHttpResponse response = HTTP_CLIENT.execute(post)) {
                        int statusCode = response.getStatusLine().getStatusCode();
                        logger.info("微信服务器响应状态码: {}", statusCode);

                        String resp = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
                        logger.info("微信服务器响应内容: {}", resp);

                        JSONObject json = new JSONObject(resp);
                        if (json.has("url")) {
                            String wechatUrl = json.getString("url");
                            logger.info("图片上传成功！微信返回的图片URL: {}", wechatUrl);
                            return wechatUrl;
                        } else if (json.has("errcode")) {
                            int errcode = json.getInt("errcode");
                            String errmsg = json.optString("errmsg", "未知错误");
                            logger.error("微信API返回错误 - errcode: {}, errmsg: {}", errcode, errmsg);

                            // 对于特定错误码，可以决定是否重试
                            if (errcode == 42001 || errcode == 40001 || errcode == 40014) { // token相关错误
                                logger.error("Token错误，不再重试");
                                return null;
                            }
                            // 对于超时相关错误，进行重试
                            if (errmsg.contains("timeout") || errmsg.contains("timeout out")) {
                                logger.warn("遇到超时错误，准备重试");
                            }
                        } else {
                            logger.error("uploadimg响应异常，无url或errcode字段: {}", resp);
                        }
                    }
                } finally {
                    // 无论成功与否，都清理临时文件
                    if (tempFile != null && tempFile.exists()) {
                        boolean deleted = tempFile.delete();
                        logger.info("临时文件删除: {}", deleted ? "成功" : "失败");
                    }
                }

                // 增加重试计数
                retryCount++;

                // 如果不是最后一次重试，等待一段时间后重试（指数退避策略）
                if (retryCount < maxRetries) {
                    long waitTime = (long) (Math.pow(2, retryCount) * 2000); // 指数退避策略，每次等待时间递增
                    logger.info("上传失败，将在 {}ms 后进行第 {} 次重试", waitTime, retryCount + 1);
                    Thread.sleep(waitTime);
                }
            } catch (Exception e) {
                retryCount++;
                logger.error("上传图文图片过程中发生异常（第{}次）: {}", retryCount, e.getMessage());

                // 如果不是最后一次重试，等待一段时间后重试
                if (retryCount < maxRetries) {
                    long waitTime = (long) (Math.pow(2, retryCount) * 2000); // 指数退避策略
                    logger.info("发生异常，将在 {}ms 后进行第 {} 次重试", waitTime, retryCount + 1);
                    try {
                        Thread.sleep(waitTime);
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        }

        logger.error("达到最大重试次数 ({})，上传失败: {}", maxRetries, imageUrl);
        return null;
    }

    /**
     * 下载文件到临时目录
     */
    private File downloadFile(String fileUrl) {
        try (InputStream in = new URL(fileUrl).openStream()) {
            File tempFile = File.createTempFile("wechat_img_", ".jpg");
            try (FileOutputStream out = new FileOutputStream(tempFile)) {
                byte[] buffer = new byte[8192];
                int len;
                while ((len = in.read(buffer)) != -1) {
                    out.write(buffer, 0, len);
                }
            }
            return tempFile;
        } catch (Exception e) {
            logger.error("下载文件失败: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 调用微信公众号API发布草稿到正式文章
     */
    private boolean publishDraftToWechat(String accessToken, String draftMediaId) {
        try {
            logger.info("准备发布草稿到微信公众号，draftMediaId: {}", draftMediaId);
            logger.info("使用的access_token: {}",
                    accessToken.substring(0, 10) + "..." + accessToken.substring(accessToken.length() - 10)); // 仅显示部分access_token，保护隐私

            // 微信公众号发布草稿的接口
            // 注意：微信API需要将access_token作为URL参数传递
            String url = "https://api.weixin.qq.com/cgi-bin/freepublish/submit?access_token=" + accessToken;
            logger.info("请求URL: {}", url.substring(0, url.indexOf("?access_token=") + 15) + "..."); // 隐藏access_token

            // 构建请求JSON
            JSONObject requestJson = new JSONObject();
            requestJson.put("media_id", draftMediaId);

            // 记录请求参数
            logger.info("构建请求参数完成，请求参数: {}", requestJson.toString());

            // 发送POST请求
            String response = sendPostRequest(url, requestJson.toString());
            if (response == null || response.isEmpty()) {
                logger.error("发布草稿响应为空");
                return false;
            }

            logger.info("收到发布草稿响应: {}", response);

            // 解析JSON响应
            JSONObject jsonResponse = new JSONObject(response);

            // 检查是否有错误码
            if (jsonResponse.has("errcode") && jsonResponse.getInt("errcode") != 0) {
                int errcode = jsonResponse.getInt("errcode");
                String errmsg = jsonResponse.getString("errmsg");
                logger.error("微信API返回错误: errcode={}, errmsg={}", errcode, errmsg);
                return false;
            }

            if (jsonResponse.has("publish_id")) {
                String publishId = jsonResponse.getString("publish_id");
                logger.info("发布草稿成功，publish_id: {}", publishId);
                return true;
            } else {
                logger.error("发布草稿失败，响应中不包含publish_id: {}", response);
                return false;
            }
        } catch (Exception e) {
            logger.error("发布草稿异常: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 调用微信公众号API发布文章（兼容旧代码的包装方法）
     */
    private boolean publishArticleToWechat(String accessToken, String title, String content, int documentId,
            List<String> imageUrls) {
        // 创建草稿，传入图片URL列表
        // 创建草稿，传入图片URL列表
        // 注意：此处无法获取文档类型，暂时不进行特殊处理
        String draftMediaId = createArticleDraft(accessToken, title, content, documentId, imageUrls, "");
        if (draftMediaId == null) {
            return false;
        }

        // 直接发布草稿（兼容原有行为）
        return publishDraftToWechat(accessToken, draftMediaId);
    }

    /**
     * 调用微信公众号API发布文章（兼容旧接口）
     */
    private boolean publishArticleToWechat(String accessToken, String title, String content, int documentId) {
        // 获取图片URL列表
        List<String> imageUrls = getImageUrlsByWenId(documentId);
        // 调用新接口
        return publishArticleToWechat(accessToken, title, content, documentId, imageUrls);
    }

    /**
     * 发送HTTP GET请求
     */
    private String sendGetRequest(String urlStr) throws IOException {
        URL url = new URL(urlStr);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        conn.setConnectTimeout(5000);
        conn.setReadTimeout(5000);

        try (InputStream in = conn.getInputStream()) {
            byte[] buffer = new byte[1024];
            int len;
            StringBuilder sb = new StringBuilder();
            while ((len = in.read(buffer)) != -1) {
                sb.append(new String(buffer, 0, len, StandardCharsets.UTF_8));
            }
            return sb.toString();
        } finally {
            conn.disconnect();
        }
    }

    /**
     * 发送HTTP POST请求 - 通过请求头传递access_token
     */
    private String sendPostRequestWithHeaders(String urlStr, String jsonBody, String accessToken) throws IOException {
        URL url = new URL(urlStr);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
        // 设置Accept-Encoding以支持UTF-8
        conn.setRequestProperty("Accept", "application/json; charset=UTF-8");
        // 在请求头中设置Authorization
        conn.setRequestProperty("Authorization", "Bearer " + accessToken);
        conn.setDoOutput(true);
        conn.setConnectTimeout(5000);
        conn.setReadTimeout(5000);

        // 使用OutputStreamWriter并明确指定UTF-8编码，而不是默认的PrintWriter
        try (OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream(), StandardCharsets.UTF_8)) {
            out.write(jsonBody);
            out.flush();
        }

        try (InputStream in = conn.getInputStream()) {
            byte[] buffer = new byte[1024];
            int len;
            StringBuilder sb = new StringBuilder();
            while ((len = in.read(buffer)) != -1) {
                sb.append(new String(buffer, 0, len, StandardCharsets.UTF_8));
            }
            return sb.toString();
        } finally {
            conn.disconnect();
        }
    }

    /**
     * 发送HTTP POST请求
     */
    private String sendPostRequest(String urlStr, String jsonBody) throws IOException {
        int maxRetries = 3;
        int retryCount = 0;
        IOException lastException = null;

        while (retryCount < maxRetries) {
            URL url = new URL(urlStr);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
            // 设置Accept-Encoding以支持UTF-8
            conn.setRequestProperty("Accept", "application/json; charset=UTF-8");
            conn.setDoOutput(true);
            // 增加超时时间，从5秒改为30秒
            conn.setConnectTimeout(30000);
            conn.setReadTimeout(30000);

            try {
                // 使用OutputStreamWriter并明确指定UTF-8编码，而不是默认的PrintWriter
                try (OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream(), StandardCharsets.UTF_8)) {
                    out.write(jsonBody);
                    out.flush();
                }

                try (InputStream in = conn.getInputStream()) {
                    byte[] buffer = new byte[1024];
                    int len;
                    StringBuilder sb = new StringBuilder();
                    while ((len = in.read(buffer)) != -1) {
                        sb.append(new String(buffer, 0, len, StandardCharsets.UTF_8));
                    }
                    return sb.toString();
                }
            } catch (SocketTimeoutException e) {
                retryCount++;
                lastException = e;
                logger.warn("请求超时，正在进行第{}次重试: {}", retryCount, urlStr);
                // 重试前等待一段时间，使用指数退避策略
                try {
                    Thread.sleep(1000 * (1 << retryCount));
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    break;
                }
            } finally {
                conn.disconnect();
            }
        }

        // 所有重试都失败后抛出最后一个异常
        if (lastException != null) {
            throw lastException;
        }

        throw new IOException("请求失败，所有重试均未成功");
    }

    /**
     * 更新文档状态
     */
    private void updateDocumentStatus(HttpServletRequest request, int documentId, int status) throws SQLException {
        Connection conn = null;
        PreparedStatement pstmt = null;

        try {
            conn = DatabaseUtil.getConnection();
            // 从会话中获取当前登录用户的user_id
            Integer userId = (Integer) request.getSession().getAttribute("userId");
            if (userId == null) {
                userId = 0; // 默认值，确保SQL不会出错
            }
            String sql = "UPDATE wk_wenku SET status = ?, edit_time = ? WHERE id = ? AND user_id = ?";
            pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, status);
            pstmt.setLong(2, System.currentTimeMillis() / 1000); // 更新编辑时间为当前时间戳（秒）
            pstmt.setInt(3, documentId);
            pstmt.setInt(4, userId);

            int affectedRows = pstmt.executeUpdate();
            logger.info("更新文档ID: {} 的状态为: {}, 影响行数: {}", documentId, status, affectedRows);
        } finally {
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    logger.error("关闭PreparedStatement失败", e);
                }
            }
            DatabaseUtil.closeConnection(conn);
        }
    }

    /**
     * 获取整型参数
     */
    private int getIntParameter(HttpServletRequest request, String paramName, int defaultValue) {
        try {
            String value = request.getParameter(paramName);
            if (value != null && !value.isEmpty()) {
                return Integer.parseInt(value);
            }
        } catch (NumberFormatException e) {
            logger.warn("参数{}格式错误，使用默认值{}", paramName, defaultValue);
        }
        return defaultValue;
    }

    /**
     * 获取微信素材的media_id
     * 使用接口: https://api.weixin.qq.com/cgi-bin/material/get_material
     */
    private String getWechatMaterialMediaId(String accessToken) {
        try {
            logger.info("准备获取微信素材的media_id");

            // 构建请求URL
            String url = "https://api.weixin.qq.com/cgi-bin/material/get_material?access_token=" + accessToken;
            logger.info("请求URL: {}", url.substring(0, url.indexOf("?access_token=") + 15) + "..."); // 隐藏access_token

            // 构建请求JSON（根据微信API文档，获取素材需要传递media_id参数）
            // 这里使用一个示例的media_id，实际应用中应该使用已存在的有效media_id
            JSONObject requestJson = new JSONObject();
            // 注意：这里需要替换为实际存在的有效素材media_id
            String sampleMediaId = "sample_material_media_id";
            requestJson.put("media_id", sampleMediaId);

            logger.info("使用的素材media_id: {}", sampleMediaId);

            // 发送POST请求
            String response = sendPostRequest(url, requestJson.toString());
            if (response == null || response.isEmpty()) {
                logger.error("获取素材响应为空");
                return null;
            }

            logger.info("获取素材响应: {}", response);

            // 解析JSON响应
            JSONObject jsonResponse = new JSONObject(response);

            // 检查是否有错误码
            if (jsonResponse.has("errcode") && jsonResponse.getInt("errcode") != 0) {
                int errcode = jsonResponse.getInt("errcode");
                String errmsg = jsonResponse.getString("errmsg");
                logger.error("获取素材失败: errcode={}, errmsg={}", errcode, errmsg);

                // 特别处理access_token无效的错误
                if (errcode == 40001) {
                    logger.error("access_token无效或已过期，请重新获取");
                    // 提示使用getStableAccessToken接口获取更稳定的access_token
                    logger.error("建议使用getStableAccessToken接口获取更稳定的access_token，详情请查看：https://mmbizurl.cn/s/JtxxFh33r");
                }
                return null;
            }

            // 素材获取成功，返回请求中使用的media_id（因为get_material接口返回的是素材内容，不是media_id）
            // 实际应用中，这里应该根据业务需求处理返回的素材内容
            logger.info("获取素材成功");
            return sampleMediaId;
        } catch (Exception e) {
            logger.error("获取素材异常: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 上传微信素材
     * 使用接口: https://api.weixin.qq.com/cgi-bin/material/add_material
     */
    private String uploadWechatMaterial(String accessToken, File file, String type) {
        try {
            logger.info("准备上传微信素材，文件路径: {}, 类型: {}", file.getAbsolutePath(), type);

            // 构建请求URL
            String url = "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=" + accessToken
                    + "&type=" + type;
            logger.info("请求URL: {}", url.substring(0, url.indexOf("?access_token=") + 15) + "..."); // 隐藏access_token

            // 确保文件存在
            if (!file.exists() || !file.isFile()) {
                logger.error("文件不存在或不是有效文件: {}", file.getAbsolutePath());
                return null;
            }

            // 创建HTTP连接
            URL requestUrl = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) requestUrl.openConnection();
            conn.setRequestMethod("POST");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(5000);

            // 设置multipart/form-data请求
            String boundary = "----WebKitFormBoundary" + System.currentTimeMillis();
            conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);

            // 写入文件数据
            try (DataOutputStream out = new DataOutputStream(conn.getOutputStream())) {
                // 文件部分
                out.writeBytes("--" + boundary + "\r\n");
                out.writeBytes(
                        "Content-Disposition: form-data; name=\"media\"; filename=\"" + file.getName() + "\"\r\n");
                out.writeBytes("Content-Type: file\r\n"); // 假设是图片类型
                out.writeBytes("\r\n");

                // 写入文件内容
                try (FileInputStream fileInputStream = new FileInputStream(file)) {
                    byte[] buffer = new byte[1024];
                    int bytesRead;
                    while ((bytesRead = fileInputStream.read(buffer)) != -1) {
                        out.write(buffer, 0, bytesRead);
                    }
                }

                out.writeBytes("\r\n");
                out.writeBytes("--" + boundary + "--\r\n");
                out.flush();
            }

            // 读取响应
            try (InputStream in = conn.getInputStream()) {
                byte[] buffer = new byte[1024];
                int len;
                StringBuilder sb = new StringBuilder();
                while ((len = in.read(buffer)) != -1) {
                    sb.append(new String(buffer, 0, len, StandardCharsets.UTF_8));
                }
                String response = sb.toString();
                logger.info("上传素材响应: {}", response);

                // 解析JSON响应
                JSONObject jsonResponse = new JSONObject(response);

                // 检查是否有错误码
                if (jsonResponse.has("errcode") && jsonResponse.getInt("errcode") != 0) {
                    int errcode = jsonResponse.getInt("errcode");
                    String errmsg = jsonResponse.getString("errmsg");
                    logger.error("上传素材失败: errcode={}, errmsg={}", errcode, errmsg);

                    // 特别处理access_token无效的错误
                    if (errcode == 40001) {
                        logger.error("access_token无效或已过期，请重新获取");
                        logger.error(
                                "建议使用getStableAccessToken接口获取更稳定的access_token，详情请查看：https://mmbizurl.cn/s/JtxxFh33r");
                    }
                    return null;
                }

                // 检查是否有media_id
                if (jsonResponse.has("media_id")) {
                    String mediaId = jsonResponse.getString("media_id");
                    logger.info("上传素材成功，获取到media_id: {}", mediaId);
                    return mediaId;
                } else {
                    logger.error("上传素材成功但未返回media_id");
                    return null;
                }
            } finally {
                conn.disconnect();
            }
        } catch (Exception e) {
            logger.error("上传素材异常: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 文档实体类
     */
    public static class Document {
        private int id;
        private String title;
        private String username;
        private String category;
        private String fileUrl;
        private int status;
        private String wenType;
        private java.math.BigDecimal price;
        private String addTime;
        private String editTime;
        private String fileExt; // 文件后缀
        private long fileSize; // 文件大小（字节）
        private int typeId; // 分类ID
        private String content; // 文档内容

        // Getters and setters
        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getCategory() {
            return category;
        }

        public void setCategory(String category) {
            this.category = category;
        }

        public String getFileUrl() {
            return fileUrl;
        }

        public void setFileUrl(String fileUrl) {
            this.fileUrl = fileUrl;
        }

        public int getStatus() {
            return status;
        }

        public void setStatus(int status) {
            this.status = status;
        }

        public String getWenType() {
            return wenType;
        }

        public void setWenType(String wenType) {
            this.wenType = wenType;
        }

        public java.math.BigDecimal getPrice() {
            return price;
        }

        public void setPrice(java.math.BigDecimal price) {
            this.price = price;
        }

        public String getAddTime() {
            return addTime;
        }

        public void setAddTime(String addTime) {
            this.addTime = addTime;
        }

        public String getEditTime() {
            return editTime;
        }

        public void setEditTime(String editTime) {
            this.editTime = editTime;
        }

        public String getFileExt() {
            return fileExt;
        }

        public void setFileExt(String fileExt) {
            this.fileExt = fileExt;
        }

        public String getFileSize() {
            return String.valueOf(fileSize);
        }

        public void setFileSize(long fileSize) {
            this.fileSize = fileSize;
        }

        public int getTypeId() {
            return typeId;
        }

        public void setTypeId(int typeId) {
            this.typeId = typeId;
        }

        public String getContent() {
            return content;
        }

        public void setContent(String content) {
            this.content = content;
        }
    }

    /**
     * 批量发布文档到微信公众号（带详细状态信息）
     */
    private Map<String, Object> batchPublishToWechatWithDetails(HttpServletRequest request, JSONArray documents,
            String officialAccountId) {
        Map<String, Object> result = new HashMap<>();
        List<Map<String, Object>> details = new ArrayList<>();
        int successCount = 0;
        int failCount = 0;

        try {
            logger.info("开始批量发布文档到公众号，文档数量: {}, 公众号ID: {}", documents.length(), officialAccountId);

            // 逐个处理文档
            for (int i = 0; i < documents.length(); i++) {
                JSONObject docInfo = documents.getJSONObject(i);
                int documentId = docInfo.getInt("id");
                String title = docInfo.getString("title");

                Map<String, Object> detail = new HashMap<>();
                detail.put("id", documentId);
                detail.put("title", title);

                try {
                    logger.info("处理文档 {}: {}", documentId, title);

                    // 调用单个文档发布方法
                    Map<String, Object> publishResult = publishToWechatWithDetails(request, documentId,
                            officialAccountId);

                    if ((Boolean) publishResult.get("success")) {
                        successCount++;
                        detail.put("success", true);
                        detail.put("mediaId", publishResult.get("mediaId"));
                        logger.info("文档 {} 发布成功", documentId);
                    } else {
                        failCount++;
                        detail.put("success", false);
                        detail.put("error", publishResult.get("message"));
                        logger.warn("文档 {} 发布失败: {}", documentId, publishResult.get("message"));
                    }
                } catch (Exception e) {
                    failCount++;
                    detail.put("success", false);
                    detail.put("error", "处理异常: " + e.getMessage());
                    logger.error("处理文档 {} 时发生异常: {}", documentId, e.getMessage(), e);
                }

                details.add(detail);
            }

            result.put("successCount", successCount);
            result.put("failCount", failCount);
            result.put("details", details);
            result.put("message", String.format("批量发布完成！成功：%d 个，失败：%d 个", successCount, failCount));

            logger.info("批量发布完成，成功: {}, 失败: {}", successCount, failCount);
            return result;

        } catch (Exception e) {
            logger.error("批量发布过程中发生异常: {}", e.getMessage(), e);
            result.put("successCount", successCount);
            result.put("failCount", failCount);
            result.put("details", details);
            result.put("message", "批量发布过程中发生异常: " + e.getMessage());
            return result;
        }
    }

    /**
     * 创建多文章合并到一个草稿
     * 
     * @param request   HttpServletRequest对象
     * @param documents 文档JSON数组
     * @param accountId 公众号ID
     * @return 包含操作结果的Map
     */
    private Map<String, Object> createMultiArticleDraft(HttpServletRequest request, JSONArray documents,
            String accountId) {
        Map<String, Object> result = new HashMap<>();
        result.put("success", false);
        result.put("draftCreated", false);
        result.put("message", "多文章草稿创建失败");
        result.put("successCount", 0);
        result.put("failCount", documents.length());

        try {
            logger.info("开始创建多文章合并草稿，文档数量: {}, 公众号ID: {}", documents.length(), accountId);

            // 获取公众号信息
            Map<String, String> accountInfo = getWechatAccountInfo(accountId);
            if (accountInfo == null || !accountInfo.containsKey("appId") || !accountInfo.containsKey("appSecret")) {
                logger.error("公众号信息不完整或不存在: {}", accountId);
                result.put("message", "公众号信息不完整");
                return result;
            }

            String appId = accountInfo.get("appId");
            String appSecret = accountInfo.get("appSecret");

            // 获取access_token
            String accessToken = getAccessToken(appId, appSecret);
            if (accessToken == null) {
                logger.error("获取微信公众号access_token失败");
                result.put("message", "获取访问令牌失败");
                return result;
            }

            // 微信公众号创建草稿的接口
            String url = "https://api.weixin.qq.com/cgi-bin/draft/add?access_token=" + accessToken;
            logger.info("请求URL: {}", url.substring(0, url.indexOf("?access_token=") + 15) + "...");

            JSONObject requestJson = new JSONObject();
            JSONArray articlesArray = new JSONArray();

            // 处理每篇文章
            int successCount = 0;
            List<String> articleTitles = new ArrayList<>();

            for (int i = 0; i < documents.length(); i++) {
                try {
                    JSONObject docInfo = documents.getJSONObject(i);
                    int documentId = docInfo.getInt("id");
                    String documentTitle = docInfo.getString("title");

                    logger.info("处理文档 {}: {} (文档ID: {})", i + 1, documentTitle, documentId);

                    // 获取文档信息
                    Document doc = getDocumentById(request, documentId);
                    if (doc == null) {
                        logger.error("未找到文档ID: {}", documentId);
                        continue;
                    }

                    // 只有已发布的文档才能发布到公众号
                    if (doc.getStatus() != 1) {
                        logger.error("文档ID: {} 未发布，不能发布到公众号", documentId);
                        continue;
                    }

                    // 构建文章内容
                    String articleTitle = doc.getTitle();
                    articleTitles.add(articleTitle);

                    // 尝试从文档URL读取实际内容
                    String documentContent = "";
                    boolean isPptOrPdf = doc.getFileExt() != null &&
                            (doc.getFileExt().toLowerCase().contains("pdf") ||
                                    doc.getFileExt().toLowerCase().contains("ppt") ||
                                    doc.getFileExt().toLowerCase().contains("pptx"));

                    if (!isPptOrPdf) {
                        documentContent = getDocumentContentFromUrl(doc.getFileUrl());
                    } else {
                        logger.info("文档ID: {} 是PPT/PDF类型，不读取实际内容", documentId);
                    }

                    // 获取文档关联的图片URL列表
                    List<String> imageUrls = getImageUrlsByWenId(documentId);

                    // 创建单篇文章的JSON对象
                    JSONObject articleJson = new JSONObject();

                    // 标题处理
                    String processedTitle = articleTitle;
                    // 预处理标题，替换特殊字符（中文引号等）为普通字符，避免Unicode转义问题
                    if (processedTitle != null) {
                        // 替换中文引号为普通引号
                        processedTitle = processedTitle.replaceAll("[\\u201c\\u201d]", "\"");
                        // 替换中文单引号为普通单引号
                        processedTitle = processedTitle.replaceAll("[\\u2018\\u2019]", "'");
                        // 替换其他可能导致问题的特殊字符
                        processedTitle = processedTitle.replaceAll("\\u00A0", " "); // 替换非断行空格

                        if (processedTitle.length() > 64) {
                            processedTitle = processedTitle.substring(0, 64);
                            logger.warn("文档ID: {} 标题过长已截断为64字符: {}", documentId, processedTitle);
                        }
                    }

                    // 内容处理
                    String processedContent = "";
                    if (!isPptOrPdf && documentContent != null) {
                        processedContent = documentContent;
                    }

                    // 添加文档关联的图片到文章正文中
                    StringBuilder imageContent = new StringBuilder();
                    if (imageUrls != null && !imageUrls.isEmpty()) {
                        for (int j = 0; j < imageUrls.size(); j++) {
                            String imageUrl = imageUrls.get(j);
                            try {
                                // 上传图片到微信服务器
                                String wechatImageUrl = uploadWechatArticleImage(accessToken, imageUrl);
                                if (wechatImageUrl != null && !wechatImageUrl.isEmpty()) {
                                    String imgTag = "<p><img src=\"" + wechatImageUrl
                                            + "\" style=\"max-width: 100%;\"></p>";
                                    imageContent.append(imgTag);
                                } else {
                                    // 备用图片标签
                                    String fallbackImgTag = "<p><img src=\"" + imageUrl
                                            + "\" style=\"max-width: 100%;\" alt=\"原始图片\"></p>";
                                    imageContent.append(fallbackImgTag);
                                }
                                // 避免请求过于频繁
                                Thread.sleep(300);
                            } catch (Exception e) {
                                logger.error("处理图片时发生异常: {}", e.getMessage());
                                String exceptionImgTag = "<p><img src=\"https://via.placeholder.com/200\" style=\"max-width: 100%;\" alt=\"异常备用图片\"></p>";
                                imageContent.append(exceptionImgTag);
                            }
                        }
                    }

                    // 将图片内容添加到文章正文
                    processedContent = imageContent.toString() + "\n\n" + processedContent;

                    // 内容长度限制
                    if (processedContent.length() > 200000) {
                        processedContent = processedContent.substring(0, 200000);
                    }

                    // 封面图上传
                    String thumbMediaId = null;
                    try {
                        if (imageUrls != null && !imageUrls.isEmpty()) {
                            thumbMediaId = uploadWechatMaterialFromUrl(accessToken, imageUrls.get(0), "image");
                        } else {
                            String defaultImageUrl = "https://static.didaproject.com/pdf/891f9b21c019f6b02f863aa9e934639b/file80.png";
                            thumbMediaId = uploadWechatMaterialFromUrl(accessToken, defaultImageUrl, "image");
                        }
                    } catch (Exception e) {
                        logger.error("上传封面图失败: {}", e.getMessage());
                    }
                    if (thumbMediaId == null) {
                        thumbMediaId = "default_thumb_media_id";
                    }

                    // 在正文末尾添加文档详情页的二维码
                    logger.info("==== 开始处理文档ID: {} 的二维码 ====", documentId);
                    // 从配置中获取二维码域名，默认使用测试环境域名
                    String currentEnv = EnvironmentManager.getInstance().getCurrentEnvironment();
                    Properties config = EnvironmentManager.getInstance().getDatabaseConfig(currentEnv);
                    String qrCodeDomain = config.getProperty("qrcodeDomain", "testdoc2.didaproject.com");
                    String qrCodeUrl = "https://" + qrCodeDomain + "/wenku/" + documentId + ".html";
                    logger.info("文档详情页URL: {}", qrCodeUrl);

                    // 对URL进行编码，确保二维码能正确识别
                    String encodedQrCodeUrl = qrCodeUrl;
                    try {
                        encodedQrCodeUrl = java.net.URLEncoder.encode(qrCodeUrl, "UTF-8");
                        logger.info("编码后的URL: {}", encodedQrCodeUrl);
                    } catch (Exception e) {
                        logger.error("URL编码失败: {}", e.getMessage());
                    }

                    // 生成二维码的第三方API地址
                    String qrCodeApiUrl = "https://api.qrserver.com/v1/create-qr-code/?size=150x150&data="
                            + encodedQrCodeUrl;
                    logger.info("使用第三方API生成二维码: {}", qrCodeApiUrl);

                    // 上传二维码图片到微信服务器
                    String wechatImageUrl = null;
                    try {
                        logger.info("上传二维码图片到微信服务器");
                        wechatImageUrl = uploadWechatArticleImage(accessToken, qrCodeApiUrl);
                        logger.info("二维码上传结果: wechatImageUrl={}", wechatImageUrl);
                    } catch (Exception e) {
                        logger.error("上传二维码到微信服务器失败: {}", e.getMessage());
                    }

                    // 如果上传失败，使用备用方案
                    if (wechatImageUrl == null || wechatImageUrl.isEmpty()) {
                        logger.warn("二维码上传失败，使用备用二维码图片");
                        wechatImageUrl = "https://mmbiz.qpic.cn/mmbiz_jpg/ciaqDnJprwv6l25XzJwibZQbJ8HM4FdF4d7V12ic6M82e3W9gAiaDZiaVicd9l6BZiaZiaFh9Vw/0?wx_fmt=jpeg";
                    }

                    // 构建二维码图片标签，使用微信返回的图片URL
                    String qrCodeImgTagFinal = "\n\n<p><strong>扫描下载</strong></p>\n<p><img src=\""
                            + wechatImageUrl + "\" style=\"width:150px;height:150px;\"></p>\n<p>文档详情页: " + qrCodeUrl
                            + "</p>";

                    // 格式化内容
                    boolean hasHtmlTags = processedContent.contains("<") && processedContent.contains(">");
                    String finalContent;
                    if (hasHtmlTags) {
                        finalContent = processedContent;
                    } else {
                        finalContent = "<p>" + processedContent.replace("\n", "</p><p>") + "</p>";
                    }

                    // 添加二维码
                    finalContent = finalContent + qrCodeImgTagFinal;

                    // 设置文章属性
                    articleJson.put("title", processedTitle);
                    articleJson.put("content", finalContent);
                    articleJson.put("digest", processedTitle);
                    articleJson.put("author", "嘀嗒文库");
                    articleJson.put("thumb_media_id", thumbMediaId);
                    articleJson.put("show_cover_pic", 0);
                    articleJson.put("need_open_comment", 0);
                    articleJson.put("only_fans_can_comment", 0);

                    // 添加到文章数组
                    articlesArray.put(articleJson);
                    successCount++;

                } catch (Exception e) {
                    logger.error("处理单篇文档时发生异常: {}", e.getMessage());
                }
            }

            // 如果没有成功处理的文章，返回失败
            if (articlesArray.isEmpty()) {
                logger.error("没有成功处理的文章，无法创建草稿");
                result.put("message", "没有成功处理的文章，无法创建草稿");
                return result;
            }

            // 设置请求参数
            requestJson.put("articles", articlesArray);

            // 发送请求创建草稿
            String response = sendPostRequest(url, requestJson.toString());
            if (response == null || response.isEmpty()) {
                logger.error("创建草稿响应为空");
                result.put("message", "创建草稿响应为空");
                return result;
            }

            // 解析响应
            JSONObject jsonResponse = new JSONObject(response);
            if (jsonResponse.has("errcode") && jsonResponse.getInt("errcode") != 0) {
                int errcode = jsonResponse.getInt("errcode");
                String errmsg = jsonResponse.optString("errmsg");
                logger.error("微信API返回错误: errcode={}, errmsg={}", errcode, errmsg);
                result.put("message", "微信API返回错误: " + errmsg);
                return result;
            }

            // 获取media_id
            String mediaId = jsonResponse.optString("media_id", null);
            if (mediaId != null) {
                logger.info("多文章合并草稿创建成功，media_id: {}, 成功处理 {} 篇文章", mediaId, successCount);

                result.put("success", true);
                result.put("draftCreated", true);
                result.put("mediaId", mediaId);
                result.put("successCount", successCount);
                result.put("failCount", documents.length() - successCount);
                result.put("message", "多文章合并草稿创建成功，共包含 " + successCount + " 篇文章");

                return result;
            } else {
                logger.error("创建草稿失败，响应中不包含media_id: {}", response);
                result.put("message", "创建草稿失败，未返回media_id");
                return result;
            }

        } catch (Exception e) {
            logger.error("创建多文章合并草稿异常: {}", e.getMessage(), e);
            result.put("message", "创建多文章合并草稿异常: " + e.getMessage());
            return result;
        }
    }

    /**
     * 批量发布文档到多个微信公众号（带详细状态信息）
     */
    public Map<String, Object> batchPublishToMultipleWechatAccounts(HttpServletRequest request, JSONArray documents,
            List<String> accountIds) {
        Map<String, Object> result = new HashMap<>();
        Map<String, Map<String, Object>> accountResults = new HashMap<>();
        int totalSuccessCount = 0;
        int totalFailCount = 0;

        try {
            logger.info("开始批量发布文档到多个公众号，文档数量: {}, 公众号数量: {}", documents.length(), accountIds.size());

            // 为每个公众号执行发布操作
            for (String accountId : accountIds) {
                try {
                    logger.info("正在发布到公众号: {}", accountId);

                    // 调用多文章合并草稿方法
                    Map<String, Object> accountResult = createMultiArticleDraft(request, documents, accountId);
                    accountResults.put(accountId, accountResult);

                    // 累计统计信息
                    totalSuccessCount += (Integer) accountResult.get("successCount");
                    totalFailCount += (Integer) accountResult.get("failCount");

                    logger.info("公众号 {} 发布完成，成功: {}, 失败: {}", accountId,
                            accountResult.get("successCount"), accountResult.get("failCount"));

                } catch (Exception e) {
                    logger.error("发布到公众号 {} 时发生异常: {}", accountId, e.getMessage(), e);

                    // 记录失败的公众号信息
                    Map<String, Object> errorResult = new HashMap<>();
                    errorResult.put("successCount", 0);
                    errorResult.put("failCount", documents.length());
                    errorResult.put("details", new ArrayList<>());
                    errorResult.put("message", "发布异常: " + e.getMessage());
                    accountResults.put(accountId, errorResult);

                    totalFailCount += documents.length();
                }
            }

            result.put("accountResults", accountResults);
            result.put("totalSuccessCount", totalSuccessCount);
            result.put("totalFailCount", totalFailCount);
            result.put("message", String.format("多公众号批量发布完成！总成功：%d 个，总失败：%d 个，涉及公众号：%d 个",
                    totalSuccessCount, totalFailCount, accountIds.size()));

            logger.info("多公众号批量发布全部完成，总成功: {}, 总失败: {}", totalSuccessCount, totalFailCount);
            return result;

        } catch (Exception e) {
            logger.error("多公众号批量发布过程中发生异常: {}", e.getMessage(), e);
            result.put("accountResults", accountResults);
            result.put("totalSuccessCount", totalSuccessCount);
            result.put("totalFailCount", totalFailCount);
            result.put("message", "多公众号批量发布过程中发生异常: " + e.getMessage());
            return result;
        }
    }
}